Stream: beginners

Topic: State machines in Roc


view this post on Zulip Henrik Larsson (Dec 16 2024 at 20:12):

How would one use phantom types in Roc to translate the following Elm example to Roc? https://sporto.github.io/elm-patterns/advanced/flow-phantom-types.html

view this post on Zulip Luke Boswell (Dec 16 2024 at 20:36):

Phantom types are supported if you use an Opaque type https://www.roc-lang.org/tutorial#opaque-types

view this post on Zulip Luke Boswell (Dec 16 2024 at 20:38):

I'm trying to think of a good example to point to, but haven't got anything yet.

I thought we had one on https://www.roc-lang.org/examples

But it doesn't look like it. I can make a PR to add on soon.

view this post on Zulip Henrik Larsson (Dec 16 2024 at 20:40):

I did try this

Order : {price : Str}
Step step : Step Order
Start : [Start]
OrderWithTotal : [OrderWithTotal ]
OrderWithQuantity : [OrderWithQuantity]
Done : [Done]

start : Order -> Step Start
setTotal : Int -> Step Start -> Step OrderWithTotal
adjustQuantityFromTotal : Step OrderWithTotal -> Step Done
setQuantity : Int -> Step Start -> Step OrderWithQuantity
adjustTotalFromQuantity : Step OrderWithQuantity -> Step Done
done : Step Done -> Order

However I do get the error
── SYNTAX PROBLEM in main.roc ──────────────────────────────────────────────────

I got stuck here:

68│ setTotal : Int -> Step Start -> Step OrderWithTotal
^

Whatever I am running into is confusing me a lot! Normally I can give
fairly specific hints, but something is really tripping me up this
time.

However its only setTotal and setQuantity that give error the other functions do type check.

view this post on Zulip Luke Boswell (Dec 16 2024 at 20:40):

Here's an example I used recently https://github.com/lukewilliamboswell/roc-experiment-js-dom/blob/0842577df83efa53a2d2584a7b38d4fb067f8f20/platform/Html.roc#L14

view this post on Zulip Luke Boswell (Dec 16 2024 at 20:41):

Here the type variable msg isn't used, it's phantom

view this post on Zulip Sam Mohr (Dec 16 2024 at 20:57):

I use plenty of Phantom types in Weaver: https://github.com/smores56/weaver/blob/3881ac2d6aeb20150e7473ab2b81b1beaf9f219c/package/SubCmd.roc#L112

view this post on Zulip Sam Mohr (Dec 16 2024 at 20:58):

The CliBuilder opaque type is:

CliBuilder data fromAction toAction := {
    parser : ArgParser data,
    options : List OptionConfig,
    parameters : List ParameterConfig,
    subcommands : Dict Str SubcommandConfig,
}

view this post on Zulip Sam Mohr (Dec 16 2024 at 20:58):

fromAction is the current state of the builder, and toAction is a possible future state

view this post on Zulip Luke Boswell (Dec 16 2024 at 21:00):

Is there like a canonical example people use for these? Something simple?

I like the idea of also showing it used with record builder for states.

view this post on Zulip Sam Mohr (Dec 16 2024 at 21:00):

In the first linked example in SubCmd, you can see that the fromAction is GetOptionsAction and the toAction is GetParamsAction. This ensures that you can only add subcommands to CliBuilders that have defined options so far, but if you defined subcommands or parameters, it won't typecheck

view this post on Zulip Sam Mohr (Dec 16 2024 at 21:01):

@Luke Boswell I'm not sure. The weaver usage is a little complex for a good teaching moment. When the tutorial rewrite happens we'll want a simpler example

view this post on Zulip Sam Mohr (Dec 16 2024 at 21:01):

I'd say the general approach of state tracking for builders is the general way I see them used

view this post on Zulip Henrik Larsson (Dec 16 2024 at 21:03):

Is there some ETA for the tutorial rewrite or will it happen when it happens ;)

view this post on Zulip Henrik Larsson (Dec 16 2024 at 21:03):

Its this we are talking about right? https://www.roc-lang.org/tutorial

view this post on Zulip Sam Mohr (Dec 16 2024 at 21:13):

Henrik Larsson said:

Is there some ETA for the tutorial rewrite or will it happen when it happens ;)

I don't think anyone currently owns it. @JanCVanB just recently added some stuff, but it's still in the form of a single, giant page. This has the benefit of implying that Roc is a small language that you can learn quickly, but it's still unwieldy in my opinion. @Richard Feldman I think was wanting to do it himself, but maybe I'm mistaken.

view this post on Zulip Sam Mohr (Dec 16 2024 at 21:16):

I think Roc would be very well served with a "tourtorial" like Gleam has, but even a mdbook-like tutorial would help digestability IMO

view this post on Zulip Sam Mohr (Dec 16 2024 at 21:17):

I think if someone felt strongly about teaching and wanted to update the tutorial, we wouldn't complain about them taking up the sword of progress

view this post on Zulip Richard Feldman (Dec 16 2024 at 21:27):

yeah I originally wanted to delay personally doing a tutorial rewrite until purity inference was out, and now I want to delay it until static dispatch and custom types have landed :big_smile:

view this post on Zulip Richard Feldman (Dec 16 2024 at 21:28):

so it'll be months, and any incremental improvements in the meantime would be both great and also would become part of the inputs to the rewrite!

view this post on Zulip Sam Mohr (Dec 16 2024 at 21:45):

Incremental updates being changes to the content of the current layout, but not any structural changes.

view this post on Zulip Richard Feldman (Dec 16 2024 at 21:47):

yeah

view this post on Zulip Brendan Hansknecht (Dec 17 2024 at 00:04):

Richard Feldman said:

yeah I originally wanted to delay personally doing a tutorial rewrite until purity inference was out, and now I want to delay it until static dispatch and custom types have landed :big_smile:

This is always my problem with docs

view this post on Zulip Brendan Hansknecht (Dec 17 2024 at 00:04):

Always something to delay for

view this post on Zulip Richard Feldman (Dec 17 2024 at 00:08):

usually I wouldn't bother if it's just small changes, but both static dispatch and purity inference are like "rewrite most to all of the examples" changes and custom types affects a large chunk too :sweat_smile:

view this post on Zulip Luke Boswell (Dec 17 2024 at 00:17):

I thought you had a larger pivot in mind. Like you've mentioned how you wanted to approach the introduction for people from another angle or something.

view this post on Zulip Richard Feldman (Dec 17 2024 at 00:20):

yeah I do :+1:

view this post on Zulip Richard Feldman (Dec 17 2024 at 00:21):

oh yeah which reminds me, for loops too :sweat_smile:

view this post on Zulip Henrik Larsson (Dec 17 2024 at 15:30):

Thanks for all the input, just for history on OP, the Roc way for state machines with phantom types based on the Elm example looks like this I think.

Order : {price : Str}
Step step := [Step Order]
Start : [Start]
OrderWithTotal : [OrderWithTotal]
OrderWithQuantity : [OrderWithQuantity]
Done : [Done]

start : Order -> Step Start
setTotal : Int *, Step Start -> Step OrderWithTotal
adjustQuantityFromTotal : Step OrderWithTotal -> Step Done
setQuantity : Int *, Step Start -> Step OrderWithQuantity
adjustTotalFromQuantity : Step OrderWithQuantity -> Step Done
done : Step Done -> Order

Last updated: Jul 06 2025 at 12:14 UTC