Since we were already talking about syntax extensions anyway…
Today we can do
x y | p y = ...
-- (using -XMultiwayIf)
x' = \ y -> if | p y -> ...
-- (using -XLambdaCase)
x'' = \ case
y | p y -> ...
x''' = \ y -> case y of
_ | p y -> ...
but for some reason the most concise version (x) only works when using the “write the function name out over and over” version of the syntax. The below does not work:
x = \ y | p y -> ...
This seems like an arbitrary restriction and I find myself wanting this exact thing very often in reality, e.g. when I want to use \ case but I need to give the scrutinee a name.
Since the above (non-working) snippet is a parse error today, it seems like this is syntactic space that hasn’t been taken up yet .
I wonder if someone had considered this syntax before. Especially in the context of the existence of MultiWayIf I find it extremely strange, if the above (non-working) syntax existed, MultiWayIf would be entirely redundant (and it would be a couple of tokens shorter, too!)
I hope to get an answer here since the history of Haskell is full of Chesterton’s fences
I don’t understand “e.g. when I want to use \ case but I need to give the scrutinee a name.” because you can give it a name as you show in the x'' example.
While this is clearly an alternative (I actually have exactly that example, it’s x’’), I think
LambdaCase is different in the sense that the lhs of the arrow is intended to be a pattern (not a binding) so it feels like it’s abusing the syntax, i.e. I expect that if I see case, then the branches are patterns and if I see |, then the branches are (pattern) guards
similarly to MultiWayIf it’s more verbose and unnecessarily (at least I think that’s the case) so
Pattern guards not being allowed to appear after a lambda seems like an “arbitrary” and “asymmetric” (in quotes because I don’t yet know what the actual reasons would be) restriction.
My thoughts are similar to this Haskell mailing list entry from 2006. It mentions that “guards were removed from Lambdas” which makes me wonder whether this has already been a feature at some point. Sadly, of course, all of the mentioned links are dead. I’ll see if the wayback machine has some.
I think most Haskellers agree that partial functions are bad, so I think it is good to have a bit of extra verbosity like \ case to dissuade you and indicate that something dangerous is going on.
Good thing I didn’t suggest partial functions. As with pattern guards in any position, if p x were non-exhaustive, you would of course get the respective exhaustiveness warning and the possibility to add new guards below.
MultiWayIf is also useful for expressions that aren’t the body of a lambda.
f a b c $ if | p -> x
| otherwise -> y
One argument against your suggestion, discovered by playing around with compiler/GHC/Parser.y for a few minutes, is that introducing guards into plain lambdas would require lambdas to participate in layout, and that changes how some currently laid-out lambdas would be parsed.
To elaborate: how is \case x | p x -> \case y | q y -> x + y | otherwise -> x - y parsed? The case to which the otherwise clause attaches is ambiguous. GHC fixes this using the layout algorithm, which inserts virtual braces, producing this unambiguous expression: \case { x | p x -> \case { y | q y -> x + y | otherwise -> x - y } }. Braces are always inserted into case lambdas (if not present), but not inserted into plain lambdas. If you want plain lambdas to be guarded, they would need to get virtual braces too, in order to avoid this same ambiguity. But the layout algorithm imposes a constraint on how the bodies of such things can be written. Plain lambdas today, which don’t have braced bodies, can be written like this without issue:
f = \x ->
\y ->
x + y
But try that with \case and you’ll get a parse error. Each \case alternative body needs to be indented at least this much:
g = \case x ->
\case y ->
x + y
If you make plain lambdas have the same layout behavior as case lambdas, then f will no longer parse.
Maybe that’s an acceptable cost for new code written with an opt-in extension, but I think most extensions should be written with an eye towards becoming standardized or deprecated, and in the long term I don’t think the cost of reformatting whatever lambdas are out there written in a non-layout-friendly way is worth the gain of unifying plain lambdas with \case. Using \case when you want guards isn’t much of a burden at all compared to negotiating a change to the layout of one of Haskell’s most central syntax elements.
Interesting observation but it seems like an insufficient argument since it does some assumptions that I am not convinced that they hold true, e g that you would have to make (all) „lambdas participate in layout“ as you call it.
Edit: in addition I’m not at the stage of „negotiating a change“ but I want to find out why things have been done a certain way in the past. Talking about what things might have happened for what reasons thankfully doesn’t require to negotiate change