Hey everyone, I'm toying around with roc and I'm trying to write a unit testable i/o example and thought I could port Seemans free monad recipe which I've used before, but I'm struggling with the pattern matching on the instructions in the map function:
In1: U8
Out1: Str
In2: U16
Out2: U32
Instruction a: [
Member1 (In1, Out1 -> a),
Member2 (In2, Out2 -> a)
]
mapI: (a -> b), (Instruction a) -> (Instruction b)
mapI = \f,i -> when i is
Member1 (a, next) -> Member1 (a, \y -> f (next y))
Member2 (a, next) -> Member2 (a, \y -> f (next y))
Compiler error:
── TYPE MISMATCH in main.roc ────────────────────────────────────────────
───────
The branches of this when expression don't match the condition:
23│> mapI = \f,i -> when i is
24│ Member1 (a, next) -> Member1 (a, \y -> f (next y))
25│ Member2 (a, next) -> Member2 (a, \y -> f (next y))
This i value is a:
[
Member1 (In1, Out1 -> a),
Member2 (In2, Out2 -> a),
]
But the branch patterns have type:
[
Member1 (
*,
*,
)c,
Member2 (
*,
*,
)f,
]
The branches must be cases of the when condition's type!
── TYPE MISMATCH in main.roc ────────────────────────────────────────────
───────
Something is off with the body of the mapI definition:
22│ mapI: (a -> b), (Instruction a) -> (Instruction b)
23│> mapI = \f,i -> when i is
24│> Member1 (a, next) -> Member1 (a, \y -> f (next y))
25│> Member2 (a, next) -> Member2 (a, \y -> f (next y))
This when expression produces:
[
Member1 (
a,
a -> b,
)b,
Member2 (
*,
* -> b,
)b,
]d
But the type annotation on mapI says it should be:
[
Member1 (In1, Out1 -> b),
Member2 (In2, Out2 -> b),
]
────────────────────────────────────────────────────────────────────────────────
2 errors and 1 warning found in 24 ms
Not set on using that pattern really, other tips for more idiomatically achieving the same kind of testable separation that hexagonal design would get me in OOP would be appreciated.
I think the parens are incorrect and that is the root issue here.
In the code above, currently Member1 contains a single value that is the lambda that take an In1
and an Out1
. It returns an a
.
Try something like:
Member1 In1 (Out1 -> a)
Then match as:
Member1 a next ->
I think that should work.
If you specifically want a tuple in Member1, you could also go for this instead:
Member1 (In1, (Out1 -> a))
But I would advise dropping the tuple and doing the above instead
All that said, no comment on hexagonal design and how to do that in Roc/what the correct thing to do in roc instead is. Not sure what hexagonal design is.
Brendan Hansknecht said:
But I would advise dropping the tuple and doing the above instead
Thank you, dropping the tuple compiles and simplifies it :sparkling_heart:
woopsie, now I'm getting a compiler error when I implement Pure a -> f a
. If replace that line with _ -> crash "TODO"
it compiles.
In1: U8
Out1: Str
In2: U16
Out2: U32
Instruction a: [
Member1 In1 (Out1 -> a),
Member2 In2 (Out2 -> a)
]
mapI: (a -> b), (Instruction a) -> (Instruction b)
mapI = \f,i -> when i is
Member1 a next -> Member1 a \y -> f (next y)
Member2 a next -> Member2 a \y -> f (next y)
Program a : [
Free (Instruction (Program a)),
Pure a
]
bind: (a -> Program b), Program a -> Program b
bind = \f, p -> when p is
Free x -> (mapI (\a -> bind f a) x) |> Free
Pure a -> f a
thread '<unknown>' has overflowed its stack
fatal runtime error: stack overflow
Hi @Krys, can you make an issue for that?
Last updated: Jul 06 2025 at 12:14 UTC