Stream: ideas

Topic: List matching at offset


view this post on Zulip Brendan Hansknecht (Mar 21 2023 at 05:26):

Do we have any plans to enable list matching at an offset?

As a simple example, Lets say I want to check for the comment identifier in c at a specific offset. If I wanted to do that at the beginning of a List, I could just do:

when bytes is
    ['\\', '\\', ..] -> # we have a comment, do things.

When dealing with an offset, you lose matching. Instead you have to do:

when List.get bytes offset is
    Ok '\\' ->
        when List.get bytes (offset + 1) is
            Ok '\\' ->
                # we have a comment, do things.

I am not sure what the merged syntax would look like exactly. Maybe something like [ ..offset, '\\', '\\', .. ], but some form of merge syntax may make for much nicer matching if dealing with an offset. Any thoughts?

view this post on Zulip Luke Boswell (Mar 21 2023 at 06:43):

Is there any reason List.get returns only a single element? What if you could specify a number of values instead?

view this post on Zulip Luke Boswell (Mar 21 2023 at 06:45):

Maybe a List.getRange or something?

view this post on Zulip Luke Boswell (Mar 21 2023 at 06:48):

I forgot about List.subList

view this post on Zulip Luke Boswell (Mar 21 2023 at 07:04):

This works, maybe there is a nice syntax sugar which does something similar?

when List.sublist myList {start: 2, len: 2} is
        ['c','d', ..] ->  Stdout.line "Yay"
        _ -> Stdout.line "Nay"

My attempts at brainstorming some ideas

# Maybe we could add an offset fn which just shifts the list by N elements
when List.offset bytes 2 is
    ['c','d'] -> ..

# Or maybe re-use the infix shift operators for Lists?
when bytes << 2 is
    ['c','d'] -> ..

view this post on Zulip Brian Carroll (Mar 21 2023 at 08:36):

Hmm those solutions will all work but will allocate a new list. And then we immediately discard that new list after getting the elements. But we already had the contents in the original list, so that's a pity.
I think the only viable solution here is to use pattern matching. I thought we had something for pattern matching on lists a while ago. I think Ayaz implemented it. Maybe it doesn't cover this case.

view this post on Zulip Ayaz Hafiz (Mar 21 2023 at 10:59):

sublist should use a slice right? and not allocate anything? am i missing something that means it doesn’t work here?

view this post on Zulip Folkert de Vries (Mar 21 2023 at 11:00):

right, with seamless slices it seems like this should work without allocating

view this post on Zulip Folkert de Vries (Mar 21 2023 at 11:00):

it may still bump the refcount of the list, but that should be it

view this post on Zulip Ayaz Hafiz (Mar 21 2023 at 11:01):

:point_up:also if the prefix is statically known you can do something like [_, _, ‘//‘, ‘//‘, ..]

view this post on Zulip Brian Carroll (Mar 21 2023 at 12:18):

Oh I forgot about slices!

view this post on Zulip Brendan Hansknecht (Mar 21 2023 at 14:28):

Seamless slice should work. Was just hoping to avoid the cost in a hot loop (even if relatively small). That is why I think a proper built-in syntax be nice. Also, if you have a list of recounted things, I'm pretty sure the performance would be terrible, but maybe that will change enough in the future to not be a concern.

view this post on Zulip Kevin Gillette (Mar 24 2023 at 13:41):

Perhaps something like: [1, 2, .., 4: 5, .., 10]

Essentially the indexed element ("value 5 at index 4") terminates the sweep/skip, and must be used whenever there are elements between two skips, and an indexed element must always be preceded by a skip.

Negative indices could perhaps indicate distance from the end. These would need to appear after all positive indices if present.

If the last element has a positive index, it must also be one less than the actual length to match. If the last contiguous sequence of elements is indexed, similarly, that index plus the length of the sequence must match the overall list length. We could disallow start-of-list positive indices and end-of-list negative indices, since they prove nothing useful (they'd need to be 0 and -1 respectively to ever match).

At least to start with, the indices must be constant, and the compiler could use them to prove a minimum list length. If at runtime, the list is not at least that length, then the match will fail, e.g. if the positive indices (or elements that trail) would go past the end of the list, if negative indices fall before the start of the list, or if negative and positive indices would swap their relative order compared to the source.

We could also support runtime-variable indices, such as with [.., i: x, .., j: y, ..]. A runtime check would need to be performed to ensure that the earlier mentioned criteria permit at match (including that x and y don't end up swapping order).


Last updated: Jun 16 2026 at 16:19 UTC