I'm wondering if there is some better way to match on these? i feel like it should be possible using an or patttern or somesuch.
LList a := [Node { data : a, next : LList a, prev : LList a }, First { data : a, next : LList a }, Last { data : a, prev : LList a }]
value = \@LList list ->
when list is
Node { data } -> data
Last { data } -> data
First { data } -> data
Looks good to me.
you can do Node { data } | Last { data } | First { data } -> data
as a single branch
has no impact on runtime performance but you might like it better in terms of style
I tried that because I thought it should work and it actually gave me a compile error complaining about shadowing.
And yes, I wasn't looking for fast performance just a cleaner representation
in this case Node r | Last r | First r -> r.data
might work?
shadowing is weird here, I would consider that a bug
Haha, yup tried that too
Also didn't work
what is the error exactly?
Jumped back on my computer:
That's your first suggestion
── DUPLICATE NAME in ./LList.roc ───────────────────────────────────────────────
The data name is first defined here:
13│ Node { data }
^^^^^^^^
But then it's defined a second time here:
14│ | Last { data }
^^^^^^^^
Since these variables have the same name, it's easy to use the wrong
one by accident. Give one of them a new name.
── DUPLICATE NAME in ./LList.roc ───────────────────────────────────────────────
The data name is first defined here:
13│ Node { data }
^^^^^^^^
But then it's defined a second time here:
15│ | First { data } -> data
^^^^^^^^
Since these variables have the same name, it's easy to use the wrong
one by accident. Give one of them a new name.
── NAME NOT BOUND IN ALL PATTERNS in ./LList.roc ───────────────────────────────
data is not bound in all patterns of this when branch
13│ Node { data }
^^^^
Identifiers introduced in a when branch must be bound in all patterns
of the branch. Otherwise, the program would crash when it tries to use
an identifier that wasn't bound!
────────────────────────────────────────────────────────────────────────────────
now the other
value2 = \@LList list ->
when list is
Node d | Last d | First d -> d.data
── TYPE MISMATCH in ./LList.roc ────────────────────────────────────────────────
The branches of this when expression don't match the condition:
12│> when list is
13│ Node d | Last d | First d -> d.data
This list value is a:
[
First {
data : a,
next : LList a,
},
Last {
data : a,
prev : LList a,
},
Node {
data : a,
next : LList a,
prev : LList a,
},
] as b
But the branch patterns have type:
[
First {
data : a,
next : LList a,
},
Last {
data : a,
next : LList a,
},
Node {
data : a,
next : LList a,
},
]
The branches must be cases of the when condition's type!
────────────────────────────────────────────────────────────────────────────────
I think my intuition is that because records are "open" in that you can require a subset and not care about the rest of them and unions are open in that same sense. However It seems that slightly unintuitively breaks down when matching union containing a record for which you only want the shared subset
Okay, this simpler example does work
fun = \tag ->
when tag is
AA t | BB t -> t.data
main =
b = AA { data: 10, other: 20 }
fun b
It's because opaque unions are closed, right? It all works fine until i get the opaque types involved
Okay so this works with a single case
Opaque := [AA { data : U64, other:U64 }]
fun = \tag ->
when tag is
AA t -> t.data
funWrap = \@Opaque tag ->
fun tag
main =
b = @Opaque (AA { data: 10, other:10 })
funWrap b
This also works when i remove other from AA
Opaque := [AA { data : U64 }, BB { data : U64 }]
fun : [AA { data : U64 }, BB { data : U64 }]* -> U64
fun = \tag ->
when tag is
AA t | BB t -> t.data
_ -> crash ""
funWrap = \@Opaque tag ->
fun tag
main =
@Opaque (AA { data: 10 }) |> funWrap
It's like we can't have both an open union and an open record at the same time.
When i try to force everything to be open with annotation things get really weird:
Opaque a b := [AA { data : U64, other : U64 } b, BB { data : U64 }a]
fun : [AA { data : U64 }*, BB { data : U64 }*]* -> U64
fun = \tag ->
when tag is
AA t | BB t -> t.data
_ -> crash ""
funWrap = \@Opaque tag ->
fun tag
main =
@Opaque (AA { data: 10 }) |> funWrap
error:
── TYPE MISMATCH in ./LList.roc ────────────────────────────────────────────────
The branches of this when expression don't match the condition:
43│> when tag is
44│ AA t | BB t -> t.data
45│ _ -> crash ""
This tag value is a:
[…]*
But the branch patterns have type:
[…]*
The branches must be cases of the when condition's type!
────────────────────────────────────────────────────────────────────────────────
My guess is that patterns just don't have enough flexibility when being nested.
Last updated: Jul 06 2025 at 12:14 UTC