Stream: beginners

Topic: \ for lambdas: was that strictly necessary?


view this post on Zulip Arialdo Martini (Nov 20 2023 at 21:40):

I'm curious about the syntax of lambdas, which like in Haskell requires a \ symbol.
I always asked myself if in theory the language could be designed to represent lambdas without \ without incurring in any ambiguity, i.e., if a -> b was enough.
I would love to have your take on this.

view this post on Zulip Richard Feldman (Nov 20 2023 at 21:52):

@Joshua Warner may have thoughts on this :big_smile:

view this post on Zulip Joshua Warner (Nov 20 2023 at 22:36):

Particularly with multiple arguments, or when using pattern matching in arguments, that will make parsing much more difficult (maybe impossible to parse unambiguously).

Even ignoring the difficulty of parsing, in practice I think this will lead to needing to put parens around the lambda in order to clear up the ambiguity.

view this post on Zulip Arialdo Martini (Nov 20 2023 at 22:43):

I understand it can help readability. But I cannot honestly think of a case where the lack of a prefix symbol could cause ambiguity

view this post on Zulip Arialdo Martini (Nov 20 2023 at 22:44):

can you share an example of an ambigue expression that would cause problems to the parser?

view this post on Zulip Joshua Warner (Nov 20 2023 at 23:09):

There are a couple cases. You can do pattern matching / destructuring in the arguments to a lambda - e.g. \Foo a b -> a+b - which both destructures a Foo tag, pulls out the two fields, and then binds those as variables in the body.

Right now you can pass that lambda as an argument to a function like so: myFunc \Foo a b -> a+b. Without the \, that becomes: myFunc Foo a b -> a+b. Is that a function call taking a closure as it's only argument? Or is that a function taking the tag Foo, the value a, and a single-argument closure b->a+b as arguments?

view this post on Zulip Joshua Warner (Nov 20 2023 at 23:10):

In order to make that unambiguous, you'd have to add parens like so: myFunc (Foo a b -> a+b)

view this post on Zulip Joshua Warner (Nov 20 2023 at 23:21):

The other case is around lambdas accepting multiple arguments - e.g. \a, b -> a+b.
This works fine in the context above (passing it as an argument) - but we run into trouble if we have to put that _anywhere inside_ parenthesis.

e.g. (a, b -> a+b) becomes ambiguous whether you mean a tuple with two fields a and b -> a+b, or a parenthesized lambda that takes two arguments. Note that this is true if it's nested anywhere, even deeply inside a parenthesized expression (or a list with [] - same thing).

view this post on Zulip Joshua Warner (Nov 20 2023 at 23:30):

Also note that there's a closely-related problem around "multi-backpassing" - e.g. a, b <- foo, that's been discussed before. That doesn't use an introducer like \, and so has same problems as above.

Currently we resolve this ambiguity by saying you can't ever use multi-backpassing anywhere inside a parenthesized expression - and that's mostly fine because needing multiple "return values" (which are really arguments) is rare.

I don't think it would fly if we made the same restriction on lambdas, particularly given that you're going to have to parenthesize them in some new cases you didn't before (see the first point).

view this post on Zulip Declan Joseph Maguire (Nov 21 2023 at 07:41):

Can't comment on the syntactic necessity, but in practice I find it an invaluable visual marker that lets me mentally parse quickly, especially for anonymous lambdas

view this post on Zulip Arialdo Martini (Nov 21 2023 at 09:06):

Very clear! Thank you very much for the insightful explanations!


Last updated: Jul 06 2025 at 12:14 UTC