Or patterns

· Allanderek's blog

#elm #syntax

Elm is famously pretty conservative when it comes to adding language features/syntax. In general I appreciate this, but or-patterns are something I have longed for for a long time. I feel they can drastically increase clarity. However I do understand that a 'better' solution may arrive and we will all be glad Elm held off on implementing or-patterns. Still I feel that in this case, it's worth the risk, or-patterns are used in a few other languages and to good effect.

# What are or-patterns

A simple implementation would simply allow you to 'stack' case branches together, here is a simple example:

 1isWeekEnd : Day -> Bool
 2isWeekEnd day =
 3    case day of
 4        Sat ->
 5        | Sun ->
 6            True
 7        Mon ->
 8        | Tue ->
 9        | Wed ->
10        | Thur ->
11        | Fri ->
12            False

You can get progressively more fancy with this. You can allow the patterns to define variables as long as all of the patterns which are stacked together define the same set of variables at the same types:

 1type alias Age = String
 2type Actor
 3    = Person Age
 4    | Animal Species Age
 6actorAge : Actor -> Age
 7actorAge actor =
 8    case actor of
 9        Person age ->
10        | Animal _ age ->
11            age

Next you can allow such or-patterns nested within other patterns:

1type alias Role = (Name, Actor)
2roleAge : Role -> Age
3roleAge role =
4    case role of
5        (_, Person age | Animal _ age) ->
6            age

Finally you could allow missing variables to be defined in the pattern, though personally I find this is probably going further than is warranted, I don't think I've ever really wanted this:

1nothingAsZero : Maybe number -> number
2nothingAsZero mNumber =
3    case mNumber of
4        Nothing n is 0 ->
5        | Just n ->
6            n

Of course these silly little examples do not really show off the power of or-patterns. They really come into their own when defining utility functions over custom types with many cases. For example, your Message type, something like:

 1isUserInteraction : Message -> Bool
 2isUserInteraction message =
 3    case message of
 4        EmailInput _ ->
 5        | PasswordInput _ ->
 6        | LoginSubmit ->
 7        ... bunch of other cases ..
 8            True
 9        LoginResponse _ ->
10        | ProfileResponse _ ->
11        | PostsResponse _ _ ->
12        ... bunch of other cases ..
13            False

# Why might something better come along?

Or-patterns do not solve all the issues with case expressions. In particular some times you need a sub-expression for some of the cases, but those cases do not have identical results. This kind of situation is awkward to describe and doesn't lend itself to short self-contained examples very well.

# Conclusion

I still think or-patterns should be introduced into Elm, or pretty much any other functional language that does not have them. I don't believe they hurt comprehension, or make the compiler particularly more complex, or make error messages more difficult (though parsing might be an issue here). I wrote a more thought out proposal a couple of years ago, and I still think it stands well: https://discourse.elm-lang.org/t/language-proposal-introduce-or-patterns/2664/7, the thread is also worth reading, some good contributions in there.