[ghc-steering-committee] Proposal #302: Multiway lambda: time to vote

Richard Eisenberg lists at richarde.dev
Sat Jul 17 18:22:29 UTC 2021



> On Jul 17, 2021, at 7:21 AM, Simon Marlow <marlowsd at gmail.com> wrote:
> 
> Hi Richard - I'm curious about the coding style that you would advocate that uses it often. Can you give an example?
> 

Sure:

> not :: Bool -> Bool
> not = \cases
>   False -> True
>   True  -> False
> 
> filter :: (a -> Bool) -> [a] -> [a]
> filter = \cases
>   _    []                   -> []
>   pred (x : xs) | pred x    -> x : filter pred xs
>                 | otherwise -> filter pred xs

This style has a few advantages over the more typical one:
- The name is not repeated each time, which is otherwise a refactoring hazard.
- The indentation of each line does not depend on the name, which is otherwise a separate refactoring hazard.
- It is possible to define a helper function in a where clause that scopes over the whole function.

Alternative version of filter

> filter :: (a -> Bool) -> [a] -> [a]
> filter pred = \cases
>   []                   -> []
>   (x : xs) | pred x    -> x : filtered
>            | otherwise -> filtered
>     where filtered = filter pred xs

This alternative has further advantages:
- It is clear which parameters are matched against and which are not (assuming the matched parameters go last).
- A `where` clause can scope over the whole function, or an individual match, depending on its indentation level.

A style more at odds with history might be

> filter :: forall a. (a -> Bool) -> [a] -> [a] = \cases
>   ...

which is even less repetitive.

Would I *require* any of this for all of Haskell? Never. But it's appealing to me in its concision and expressive power.

Richard


More information about the ghc-steering-committee mailing list