Stream: beginners

Topic: porting interpreter example from f# to roc


view this post on Zulip Krys (Aug 15 2024 at 14:52):

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.

view this post on Zulip Brendan Hansknecht (Aug 15 2024 at 15:02):

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.

view this post on Zulip Brendan Hansknecht (Aug 15 2024 at 15:04):

Try something like:
Member1 In1 (Out1 -> a)

Then match as:
Member1 a next ->

view this post on Zulip Brendan Hansknecht (Aug 15 2024 at 15:04):

I think that should work.

view this post on Zulip Brendan Hansknecht (Aug 15 2024 at 15:06):

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

view this post on Zulip Brendan Hansknecht (Aug 15 2024 at 15:08):

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.

view this post on Zulip Krys (Aug 15 2024 at 15:29):

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:

view this post on Zulip Krys (Aug 15 2024 at 16:25):

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

view this post on Zulip Anton (Aug 16 2024 at 09:28):

Hi @Krys, can you make an issue for that?


Last updated: Jul 06 2025 at 12:14 UTC