Stream: beginners

Topic: How to migrate modules


view this post on Zulip Aurélien Geron (Jun 23 2026 at 00:24):

I'm looking into migrating some libraries to the new compiler, starting with roc-parser and unicode. Most of it looks fairly straightforward, but I'm not entirely sure how to reorganize modules. For example, in roc-parser, the Xml module currently starts like this:

module [Xml, XmlDeclaration, XmlVersion, Node, Attribute, xml_parser]

import Parser exposing [Parser, const, map, skip, keep, one_or_more, one_of, many, between, alt, chomp_while, flatten, lazy, chomp_until]
import String exposing [parse_str, string, Utf8, digits, codeunit_satisfies]

Xml : {
    xml_declaration : [Given XmlDeclaration, Missing],
    root : Node,
}

XmlDeclaration : {
    version : XmlVersion,
    encoding : [Given XmlEncoding, Missing],
}

XmlVersion := {
    after_dot : U8,
}
    implements [Eq]

v1_dot0 : XmlVersion
v1_dot0 = @XmlVersion(
    {
        after_dot: 0,
    },
)
...
expect ...
...
xml_parser : Parser Utf8 Xml
xml_parser =
    const(
        |xml_declaration|
            |root| {
                xml_declaration,
                root,
            },
    )
    |> keep(p_prolog)
    |> keep(p_element)
    |> skip(many(p_whitespace))
...

Should I migrate it to something like this?

import Parser exposing [Parser, const, map, skip, keep, one_or_more, one_of, many, between, alt, chomp_while, flatten, lazy, chomp_until]
import String exposing [parse_str, string, Utf8, digits, codeunit_satisfies]

Xml := {
    xml_declaration : [Given(XmlDeclaration), Missing],
    root : Node,
}. {

XmlDeclaration : {
    version : XmlVersion,
    encoding : [Given(XmlEncoding), Missing],
}

XmlVersion := {
    after_dot : U8,
}.{
    is_eq : XmlVersion, XmlVersion -> Bool
    is_eq = |v1, v2| v1.after_dot == v2.after_dot
}

v1_dot0 : XmlVersion
v1_dot0 = { after_dot: 0 }

...

xml_parser : Parser(Utf8, Xml)
xml_parser = {
    const(
        |xml_declaration| {
            |root| { {xml_declaration, root } }
        }
    )
    .keep(p_prolog)
    .keep(p_element)
    .skip(many(p_whitespace))
}
...
}

expect { ... }

Specifically:

view this post on Zulip Jonathan (Jun 23 2026 at 08:52):

I can answer a couple I think

» f = |a, b| {a, b}
assigned `f`
» f(1, 2)
{ a: 1.0, b: 2.0 }

Personal preference

view this post on Zulip Jonathan (Jun 23 2026 at 08:57):

I was also looking into migrating roc-parser but was blocked by #9670 last I checked. It did seem like much of it could be migrated over quite mechanically besides some cases I hit where the return type had to be decoupled from the input, e.g.

match result {
    # this
    Ok({key1, key2}) => Ok({key1, key2})
    # but not
    Ok(_) as ok_res => ok_res
}

which also seemed to affect map_ok idioms.

view this post on Zulip Jonathan (Jun 23 2026 at 08:59):

You will be much faster than me and I didn't really have any major API suggestions either (besides maybe some conveniences over curried const arguments and keep/apply redundancy), but I'd be glad to help porting libraries needed for Exercism as well.

view this post on Zulip Jonathan (Jun 23 2026 at 09:16):

I can open a draft PR for roc-parser if you'd like to track progress, but I'm conscious that this is a blocker for you and I haven't been finding much time recently.

view this post on Zulip Luke Boswell (Jun 23 2026 at 10:15):

It looks like @Jared Ramirez has this fixed in https://github.com/roc-lang/roc/pull/9688 maybe... but that just needs updating / review

view this post on Zulip Luke Boswell (Jun 23 2026 at 10:16):

I think I missed that... and I'm travelling for work for a couple of days so I probably wont be able to land that until later in the week.

view this post on Zulip Luke Boswell (Jun 23 2026 at 10:17):

@Anton would you be able to look at Jared's PR?

view this post on Zulip Jared Ramirez (Jun 23 2026 at 20:24):

thanks Anton! that's ready to go once CI finishes (usually by the time CI finishes, something else has landed the branch gets out of date, then I rebase and re-run CI, and around we go haha)

view this post on Zulip Aurélien Geron (Jun 24 2026 at 07:49):

Jonathan said:

I can open a draft PR for roc-parser if you'd like to track progress, but I'm conscious that this is a blocker for you and I haven't been finding much time recently.

Oops, I just saw your message now.

I've opened https://github.com/lukewilliamboswell/roc-parser/pull/30

view this post on Zulip Jonathan (Jun 24 2026 at 11:22):

Didn't want to leave a review comment because it felt a bit too close to personal preference :laughing: but one difference I noticed was if in some cases reducing the curried function nesting might help communicate the intent better. For instance with between I find that putting the const selector in one line shows the dropping of the first and last parse results.

    between = |parser, open, close| {
        const(|_| |val| |_| val)
            .apply(open)
            .apply(parser)
            .apply(close)
    }

Again that may just be my preference, and I'm not up to date with the evolving Roc style either.


Last updated: Jul 23 2026 at 13:15 UTC