Stream: beginners

Topic: Pattern matching on lists?


view this post on Zulip Qqwy / Marten (Jul 12 2022 at 08:15):

Roc does not support pattern matching on lists. This was probably a conscious choice. What is the reason behind it?

view this post on Zulip Anton (Jul 12 2022 at 08:27):

I think it was for performance but I don't remember the details.

view this post on Zulip Anton (Jul 12 2022 at 08:30):

This would also be a good question to add to our FAQ

view this post on Zulip Martin Stewart (Jul 12 2022 at 08:44):

It's already there :smiley: https://github.com/rtfeldman/roc/blob/trunk/FAQ.md

No :: operator, or :: pattern matching for lists. Both of these are for the same reason: an Elm List is a linked list, so both prepending to it and removing an element from the front are very cheap operations. In contrast, a Roc List is a flat array, so both prepending to it and removing an element from the front are among the most expensive operations you can possibly do with it! To get good performance, this usage pattern should be encouraged in Elm and discouraged in Roc. Since having special syntax would encourage it, it would not be good for Roc to have that syntax!

view this post on Zulip Folkert de Vries (Jul 12 2022 at 08:49):

exact matches like [ a, b, c ] -> foo are efficient though, and can skip bounds checks versus the manual List.gets

view this post on Zulip Folkert de Vries (Jul 12 2022 at 08:49):

so we should maybe revisit this at some point

view this post on Zulip Martin Stewart (Jul 12 2022 at 09:18):

What makes :: pattern matching slow is that Roc has to create a new list with one fewer items right? Maybe there could be something like a :: _ -> foo so long as the user never gets to use the _ part? Maybe the syntax could be changed to [ a, ... ] -> foo or something to make it more clear that you can't get the rest of the list. This syntax would also let you write [ ..., a ] -> foo since I believe that is also efficient (and isn't something you can do in Elm as it is very inefficient there!).

view this post on Zulip Folkert de Vries (Jul 12 2022 at 09:29):

right, that is just equivalent to a List.get

view this post on Zulip Richard Feldman (Jul 12 2022 at 11:14):

:thinking: what would be the advantage of that syntax over calling List.get directly?

view this post on Zulip Folkert de Vries (Jul 12 2022 at 11:15):

well you can do [ a, b, c, ... ]

view this post on Zulip Martin Stewart (Jul 12 2022 at 11:17):

That and no bounds check on the List.get

view this post on Zulip Martin Stewart (Jul 12 2022 at 11:17):

Maybe you could even do fancy things like [ a, ..., b ]

view this post on Zulip Folkert de Vries (Jul 12 2022 at 11:18):

well [ a, ... ] would do a bounds check to check that there is one element there

view this post on Zulip Folkert de Vries (Jul 12 2022 at 11:18):

but for [ a, b, c, ... ] you do only one bounds check instead of 3

view this post on Zulip Martin Stewart (Jul 12 2022 at 11:18):

Ah, true

view this post on Zulip J.Teeuwissen (Sep 13 2022 at 08:41):

This feature would be similar to C# list patterns. An advantage over List.get directly without using the ... is that you can do the following:

printStringList = \list ->
    when list is
        [item] -> item
        oth -> Num.toStr (List.len oth)

otherwise you have to do something like this

printStringList = \list ->
    when List.get list 0 is
        Err OutOfBounds -> Num.toStr 0
        Ok item ->
            when List.get list 1 is
                Err OutOfBounds -> item
                Ok _ -> Num.toStr (List.len list)

to avoid double invalid paths (perhaps could be written better, let me know).

view this post on Zulip Brendan Hansknecht (Sep 13 2022 at 14:45):

You can make it more compact in this case:

printStringList = \list ->
    when T (List.get list 0) (List.len list) is
        T (Ok item) 1 -> item
        T _ len -> Num.toStr len

Last updated: Jul 05 2025 at 12:14 UTC