The Ultimate Conditional Syntax
The paper introduces a new pattern-matching syntax for functional programming, enhancing expressiveness and readability, supporting complex matches, and ensuring semantics preservation through a desugaring process for integration into existing languages.
Read original articleThe paper "The Ultimate Conditional Syntax" by Luyu Cheng and Lionel Parreaux, published in the Proceedings of the ACM on Programming Languages, introduces a new pattern-matching syntax designed to enhance expressiveness and readability in functional programming languages. The authors argue that existing pattern-matching features, while useful, can be complex and cumbersome. Their proposed syntax allows for parallel and nested matches interleaved with computations and intermediate bindings, utilizing a mechanism for condition-splitting to streamline common conditional prefixes. This new syntax is exemplified within the context of MLscript, a programming language in the ML family. The authors detail a desugaring process that translates their rich syntax into a minimal core syntax, which is easier to understand and implement. They also provide a formal proof that this translation preserves semantics, ensuring that the new syntax can be effectively integrated into current and future programming languages. The work aims to rethink pattern matching, making it more powerful and intuitive for developers.
- The new syntax enhances expressiveness and readability in functional programming.
- It supports parallel and nested matches with interleaved computations.
- A desugaring process simplifies the syntax into a minimal core version.
- The translation from core syntax is proven to be semantics-preserving.
- The proposed syntax can be integrated into existing programming languages.
Related
Grokking the Sequent Calculus (Functional Pearl)
The paper introduces the lambda-mu-mu-calculus as a term assignment system for the sequent calculus, emphasizing its symmetry and suitability for compiler intermediate languages. It targets a broader audience and will be presented at ICFP '24.
Evolving languages faster with type tailoring
A proposed solution called "type tailoring" enhances type systems using metaprogramming, allowing better type inference for constructs like regex. The approach aims to improve programming language usability and efficiency.
Ask HN: Why do people say "Lisp has no syntax"? It has infinite syntax
The author discusses Lisp's syntax, highlighting its list-based structure and challenges with constructs like `cond`. They conclude that Lisp's complexity resembles other languages, despite its unique features.
Lisp macros and read work because of a bug in the original definition of Lisp
M-LISP is a new LISP dialect that integrates operational semantics with metalinguistic features, addressing inconsistencies through eval and reify operators while enhancing the understanding of LISP's semantics and functional programming.
Emit
Advancements in the Factor programming language enhance logic block extraction and reuse. A new syntax for named local variables improves clarity, demonstrated through practical examples, and encourages experimentation in the locals.lazy vocabulary.
Another nice aspect of making guards a less special case is that it avoids complexities in deciding if a binding is unused. I believe this logic was a source of lots of compiler warning bugs in ocaml.
This syntax doesn’t seem to solve the following problem with matching where there are two paths to the same binding, (say you have an option in one branch but it isn’t optional in the other, and maybe you’d like to handle both cases with the same code. Currently you can do that with a match (match …) with … pattern.
I worry that the semantics around exhaustiveness and mutable values may be confusing, though I guess OCaml already has that problem:
type t = { mutable x : bool }
let n = function true -> 1 | false -> 0
let f t =
match t with
| { x = false } when ( t.x <- true; false) -> -1
| { x } -> n x * 2 + n t.x
What does t { x = false } return? Similarly if you changed the second case to be two cases instead of binding x? if foo(args)
== 0 then "null"
|> abs
> 100 then "large"
< 10 then "small"
else "medium"
That last syntax took me a while to parse in the paper, but I can imagine numerous places in our everyday code where such syntax would more concisely capture intent.Wait a sec ... ML has the pipe of Elixir? Damn, I didn't know that!
I like the brevity, but I don't like the (at least visual) need to indent or whitespace focus. I guess I am too much a sucker for S-expressions now. But a similar structure could probably be written as a macro in a lisp, avoiding any whitespace focus or even dependency on it.
def getNaturalName(tag, globals)
if globals.lookup("0") is Just(Global(_, _, term))
if term is Numeral(_, type, _)
return Just(Name(getTermTag(type)))
error showSyntaxError("0 must be a numeral to use numerals", tag)
return Void
Though this ultimate conditional syntax is more general because lambda zero only allows one destructuring per conditional to simplify parsing.Imagine Left and Right contained data of compatible types, then I'd like to extract that data (regardless of tag) like so:
if x is Left(y) or x is Right(y) then ...
That way I only need to write the `...` part once. (This could be combined with the rest of the pattern matching machinery in interesting ways, and would probably need to have eager matching / short-circuiting semantics in case both cases match). def agent(data, predicate, fns):
ps = map(predicate, data)
fs = map(lambda x:fns[x], ps)
return map(fs, data)
Basically you want to apply one of N functions to each of the items in your data iterable, so you have a predicate to figure out which function to apply first. The degenerate case is when you have just 2 functions and your predicate returns a boolean (0 or 1).This is "agent" from J: https://code.jsoftware.com/wiki/Vocabulary/atdot#agent
with true <- is_email_address?(email),
true <- String.length(code) === 6,
%EmailConfirmation{} <- EmailConfirmations.get_email_confirmation(email),
nil <- EmailAddresses.get_email_address(email),
{:ok, user} <- Users.create_user(data),
{:ok, email_address} <- EmailAddresses.create_email_address(user, email) do
...
else
...
end
Also,
> all the branches in the corresponding pattern matching expression would need to destructure the pair, even when only one of its components is needed
Can't one just bind the unneeded component to _ ? Isn't that actually a good thing, as it clearly self-documents we won't need that value on that branch?
It reminds me a lot of the kind of flow you get in mathematics sometimes. I guess theorem prover languages may be keen to adopt it.
I'd be less keen in a language with side effects, unless the language has a way to restrict it to pure functions
Not the implementation, I think one could do better, but the fact that they identified an interesting opportunity: coming up with the Ultimate Conditional Syntax for pattern matching.
I would love to see them take one more crack at it, and this time try to think about how to reduce the syntax to the bare minimum.
Here's my read/adding of this language to PLDB: https://www.youtube.com/watch?v=UzsDaq0UdnM
if (x === 1) console.log(“it’s 1”)
The “if” bothers me though, be nice not to have it.Related
Grokking the Sequent Calculus (Functional Pearl)
The paper introduces the lambda-mu-mu-calculus as a term assignment system for the sequent calculus, emphasizing its symmetry and suitability for compiler intermediate languages. It targets a broader audience and will be presented at ICFP '24.
Evolving languages faster with type tailoring
A proposed solution called "type tailoring" enhances type systems using metaprogramming, allowing better type inference for constructs like regex. The approach aims to improve programming language usability and efficiency.
Ask HN: Why do people say "Lisp has no syntax"? It has infinite syntax
The author discusses Lisp's syntax, highlighting its list-based structure and challenges with constructs like `cond`. They conclude that Lisp's complexity resembles other languages, despite its unique features.
Lisp macros and read work because of a bug in the original definition of Lisp
M-LISP is a new LISP dialect that integrates operational semantics with metalinguistic features, addressing inconsistencies through eval and reify operators while enhancing the understanding of LISP's semantics and functional programming.
Emit
Advancements in the Factor programming language enhance logic block extraction and reuse. A new syntax for named local variables improves clarity, demonstrated through practical examples, and encourages experimentation in the locals.lazy vocabulary.