Stream: contributing

Topic: Porting parser and random


view this post on Zulip Jonathan (Jun 11 2026 at 12:15):

I've begun to want to write some random scripts during work in Roc, and often it involves "parsing" insofar as trimming leading numeric prefixes from a string. I understand that the stance is to lean on a more sophisticated parser for this (though I feel that -- being so simple and quick n dirty -- it is an excellent use case for something along the lines of Regex.trim_prefix), so unless someone else is working on it, would it be a good candidate for a relative novice/intermediate to tackle porting?

The same applies to roc-random, which would be useful for testing and benchmarking algorithms and datastructures in roc.

view this post on Zulip Richard Feldman (Jun 11 2026 at 12:31):

yeah go for it!

view this post on Zulip Luke Boswell (Jun 11 2026 at 13:12):

Would love any assistance porting over roc-random, roc-parser, or any of the libraries I kind of adpted alng the way

view this post on Zulip Luke Boswell (Jun 11 2026 at 13:13):

There is a lot of opportunity to improve those, not just port 1-1 -- so if you are interested in the API design aspect there is lots of experiments and things to try out.

view this post on Zulip Luke Boswell (Jun 11 2026 at 13:15):

They don't need to be perfect or anything... even just something rough as a first pass is better than nothing and at this stage would really help to find issues early or validate different design assumptions (like the way apps/packages/platform work together).

view this post on Zulip Luke Boswell (Jun 11 2026 at 13:20):

Also FYSA for anyone interested... there is a test package that is a direct port of the roc-parser core in the repo -- https://github.com/roc-lang/roc/blob/main/test/package_simple_parser/Parser.roc

We were using that to help validate the lambda sets implementation.

view this post on Zulip Luke Boswell (Jun 11 2026 at 13:21):

Now that I'm looking at that... the comment about being blocked is no longer valid, and so we should be good to add more combinators and capability to that.

view this post on Zulip Jonathan (Jun 15 2026 at 21:50):

Luke Boswell said:

Now that I'm looking at that... the comment about being blocked is no longer valid, and so we should be good to add more combinators and capability to that.

Was this the limiting factor for why you went without apply, const etc in the version embedded in roc? There seems to be a difference in API too. E.g., keep in roc-parser is

keep : Parser(input, (a -> b)), Parser(input, a) -> Parser(input, b)

and in the embedded module

keep : Parser(input, a), Parser(input, b) -> Parser(input, b)

view this post on Zulip Jonathan (Jun 15 2026 at 21:53):

(Which is much more intuitive to me at first sight)

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

The version in roc-parser was written by hand and battle tested.

The version in the repo was written to help flush out bugs and help us validate the machinery for compiling this kind of thing. It would be good to make it as realistic as possible so we can be more confident that everything works correctly until a real parser package gets published.

So this is most likely detail that is overlooked, not a deliberate design or anything, and I wouldn't be surprised if the version in the roc tests needs some love.

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

Got it. I'm not well versed in parser combinators, so to clarify - it's my understanding that the first style is close to applicative parsers, and is done that way so that the api is convenient to use with record builders?

view this post on Zulip Luke Boswell (Jun 16 2026 at 09:52):

I'm not sure about the difference -- it wasn't an intentional design change or anything. The limiting factor for not including the other combinators (or using the same shape) in the version in roc repo was just that there were type system bugs that prevented it. No one has gone back and updated it since.

view this post on Zulip Jonathan (Jun 16 2026 at 10:04):

Just had a penny-drop moment :slight_smile: The version in the repo is simpler and similar to what I'm used to / expect, but the roc-parser uses curried functions to thread accumulated data through the parser, much cooler :smile: I'll get back to you when I'm a bit further along.

view this post on Zulip Jonathan (Jun 16 2026 at 13:18):

I'm getting a type mismatch error where the displayed types appear equal. I can't seem to get this to work (split up and annotated for better errors):

    sep_by : Parser(input, a), Parser(input, sep) -> Parser(input, List(a))
    sep_by = |parser, separator| {
        co : Parser(input, List(a))
        co = const([])

        sb1 : Parser(input, List(a))
        sb1 = sep_by1(parser, separator)

        alt(sb1, co)
    }
-- TYPE MISMATCH ---------------------------------

This expression is used in an unexpected way:
    ┌─ /Users/jrp2018/repos/roc-parser-fork/package/Parser.roc:385:15
    │
385 │         sb1 = sep_by1(parser, separator)
    │               ^^^^^^^^^^^^^^^^^^^^^^^^^^

It has the type:

    Parser(input, List(a))

But the annotation say it should be:

    Parser(input, List(a))

I'm imagining this has something to do with polarity or generalisation? So far I've been able to circumvent similar issues by avoiding ? and making sure to re-wrap return values. Practically, this involved changing the contents of apply from

            { val: fun_val, input: rest } = fun_parser.parse_partial(input)?
            parse_partial(val_parser, rest).map_ok(
                |{ val: val, input: rest2 }| { val: fun_val(val), input: rest2 }
            )

to

            match fun_parser.parse_partial(input) {
                Err(msg) => Err(msg)
                Ok({val: fun_val, input: rest}) => {
                    match parse_partial(val_parser, rest) {
                        Ok({val, input: rest2}) => {
                            Ok({ val: fun_val(val), input: rest2 })
                        }
                        Err(msg2) => Err(msg2)
                    }
                }
            }

(map_ok seemed to cause an issue as well as ?: the callsite of apply would have a similar error as shown above).

In this case I thought it could be related to the "floating"/unpinned input parameter of the returned Parser from const

    const : a -> Parser(_input, a)

but creating const_alt : a, Parser(input, x) -> Parser(input, a) in order to use the dummy parser supplied as argument to 'connect' the inputs also didn't help (making it very clear I have no idea how inference works :smile:). It's been a bit messy trying to reduce this but I can supply a minimal example in an issue if something isn't already in the works?

view this post on Zulip Luke Boswell (Jun 16 2026 at 13:34):

Yes please, a GH issue with a minimal repro would be great :thank_you:

view this post on Zulip Jared Ramirez (Jun 16 2026 at 14:43):

I can look into this once the minimal repro is up! I suspect this is in a similar vein to some of the other type issues we've been seeing around local decls with rigid vars

view this post on Zulip Jonathan (Jun 16 2026 at 15:31):

Couldn't figure out how to reduce it closer to the underlying problem, but stripped out the rest so hope it isn't too tricky to work with https://github.com/roc-lang/roc/issues/9670

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

Jared - just reading that PR, I thought I should mention that I added the type annotations in order to make the error clearer for me to try and interpret when I was narrowing down the problem (at some point, it was something like a type mismatch where the inferred type was Parser(...) -> _ret but I'll come back to that if there's still problems later) Without any annotations, you still get

It has the type:

    Parser(input, List(a))

But the annotation say it should be:

    Parser(input, List(a))

I'm not sure if this is a separate problem or part of the family of problems as mentioned in one commit.

view this post on Zulip Jared Ramirez (Jun 17 2026 at 01:30):

Thanks! I was looking at it briefly today and I think this issue is actually orthogonal to the other rigids issue. But either way, hoping to finish investigating tomorrow and PRing a fix!

view this post on Zulip Jared Ramirez (Jun 17 2026 at 19:43):

have a fix for this up here: https://github.com/roc-lang/roc/pull/9688

view this post on Zulip Jonathan (Jun 17 2026 at 20:27):

Thank you Jared!

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

Just noticed this thread, I might have duplicated some of this work. I've started porting roc-parser, starting with Parser.roc and String.roc, see this draft PR: https://github.com/lukewilliamboswell/roc-parser/pull/30

The 3 tests in Parser.roc pass successfully, but only one at a time, otherwise I get a segfault. I opened this issue: https://github.com/roc-lang/roc/issues/9796

view this post on Zulip Luke Boswell (Jun 25 2026 at 01:01):

Thank you for working through this :smiley:

view this post on Zulip Aurélien Geron (Jun 25 2026 at 05:18):

Oh cool, all the tests now pass for Parser.roc and String.roc! The segfault was due to the ParseResult type. I've simply removed it for now (will add it back when issue #9796 is resolved).

view this post on Zulip Luke Boswell (Jun 25 2026 at 05:22):

One question... does this impact on the API we should use for roc-parser https://github.com/roc-lang/roc/pull/9736 ??

view this post on Zulip Aurélien Geron (Jun 25 2026 at 08:27):

Mmh, I didn't know about #9736, I'll read it now.
In the meantime, I've migrated CSV.roc, HTTP.roc, and Markdown.roc. All the tests pass, except for one in Markdown (the code one), which produces a really weird bug, I might need some help on this one (see my draft PR).
I'm migrating Xml.roc.
Note: in HTTP.roc, I've used U64.to_u16_wrap and U64.to_u8_wrap for now because I didn't know how to handle errors there, as it's deeply nested inside parsers and I'm not sure how to bubble up a parsing error.

view this post on Zulip Aurélien Geron (Jun 25 2026 at 09:51):

Ok, I've mostly migrated Xml.roc, but I'm stuck with a "Circular Value Definition" error. Specifically, a CDATA section can contain another CDATA section, so I'm getting this error message:

-- CIRCULAR VALUE DEFINITION ---------------------

The value p_cdata_section_content is part of a recursive non-function definition cycle.

Only functions can be recursive. Non-function top-level values must be fully computable without depending on themselves through other values.

    ┌─ /Users/ageron/dev/roc/roc-parser/package/Xml.roc:552:9
    │
552 │       .keep(p_cdata_section_content)
    │             ^^^^^^^^^^^^^^^^^^^^^^^

The code uses Parser.lazy() to solve this issue, but it's not working anymore with the new compiler. I'll file an issue.

The same problem affects p_element since an XML element can contain another XML element.

I've also had to extract Version and Node to separate type modules XmlVersion.roc and XmlNode.roc. Once #9736 is resolved, it should be possible to put them back inside Xml.

view this post on Zulip Aurélien Geron (Jun 25 2026 at 10:30):

Luke Boswell said:

does this impact on the API we should use for roc-parser https://github.com/roc-lang/roc/pull/9736

For now I'm just doing a one-to-one migration, not trying to change the API at all. Although a migration is usually a good opportunity to update the API, I feel like I don't have enough experience with Roc or roc-parser for that.

view this post on Zulip Aurélien Geron (Jun 25 2026 at 10:55):

Got the letters.roc example working. :grinning:

view this post on Zulip Aurélien Geron (Jun 25 2026 at 11:04):

The numbers.roc example looks good but it's causing a segfault. I think I'll call it a day! :sweat_smile:

view this post on Zulip Luke Boswell (Jun 25 2026 at 11:09):

Yeah, I feel you. :smiley:

view this post on Zulip Aurélien Geron (Jun 27 2026 at 09:09):

I found out why Markdown.code was failing: List.fold_rev expects |item, state| ... while the old List.walk_backwards expected |state, item| .... I fixed the code so now all the tests pass for Markdown. :blush:

The last one is Xml.roc. @Richard Feldman fixed the circular value issue and issue #9796, but I'm running into another segfault. :sweat_smile: I'll file an issue.

view this post on Zulip Aurélien Geron (Jun 27 2026 at 10:57):

All of the Roc code is migrated, but not all of it works yet:

I'm struggling to create a minimal code example for the segfaults. @Richard Feldman , do you think you could take a look at the code directly in draft PR #30?

view this post on Zulip Luke Boswell (Jun 27 2026 at 11:14):

I'm glad your finding segfaults... because I've hit that in roc-ray and it's also been hard to reduce. These will be easier to minimise because the platform is simpler.

My approach has been letting Claude swing off a debugger, it usually works well. I can't look at thees right now, but probably tomorrow.

view this post on Zulip Aurélien Geron (Jun 28 2026 at 13:29):

I've started porting the unicode library too, see Draft PR #31. I've got all the package/*.roc code migrated to the new syntax, except for GraphemeTest*.roc: I'm running into segfaults. For the migrated code, all the tests pass. :+1:

One issue I've run into is how to implement to_u32:

CodePoint :: U32.{
    from_u32 = |u32| U32.{u32}
    to_u32 = |cp| ????
}

I've worked around this temporarily like this:

CodePoint :: {u32: U32}.{
    from_u32 = |u32| {u32}
    to_u32 = |{u32}| u32
}

view this post on Zulip Austin Clements (Jun 28 2026 at 15:08):

I was curious about the same thing with unwrapping the value of an opaque type, I saw somewhere in the builtins use a convention of { self : U32 } but yeah I was wondering is it possible to access the inner value without making it a record?

view this post on Zulip Anton (Jun 28 2026 at 15:51):

Yeah, I don't think that is possible right now. Do we want to add syntax for this @Richard Feldman?

view this post on Zulip Richard Feldman (Jun 28 2026 at 15:53):

yeah this came up in another thread - I don't think @Jared Ramirez added support for it yet :smile:

view this post on Zulip Jared Ramirez (Jun 28 2026 at 20:19):

this will be fixed in this PR: https://github.com/roc-lang/roc/pull/9851

CodePoint :: U32.{
    from_u32 = |u32| CodePoint.(u32)
    to_u32 = |CodePoint.(u32)| u32
}

view this post on Zulip Richard Feldman (Jun 29 2026 at 11:39):

Aurélien Geron said:

I'm struggling to create a minimal code example for the segfaults. Richard Feldman , do you think you could take a look at the code directly in draft PR #30?

@Aurélien Geron this should be fixed on current main by this PR, lmk if you're still encountering any issues!

view this post on Zulip Aurélien Geron (Jun 29 2026 at 13:11):

Thanks @Richard Feldman , all the tests in Xml.roc now pass! :tada:
However, roc test HTTP.roc seems stuck in an infinite loop.

view this post on Zulip Richard Feldman (Jun 29 2026 at 13:11):

ha, ok I can look at that next! Same PR?

view this post on Zulip Aurélien Geron (Jun 29 2026 at 13:12):

Yes, same PR. :+1:

view this post on Zulip Aurélien Geron (Jun 29 2026 at 13:13):

Note: it was working before.

view this post on Zulip Richard Feldman (Jun 29 2026 at 18:16):

@Aurélien Geron https://github.com/roc-lang/roc/pull/9874 fixes it for me (might take a bit to land though!)

view this post on Zulip Austin Clements (Jul 02 2026 at 23:42):

Just thinking about the API for roc-random, wanted to get people's thoughts.

1) Would it make sense to make the random seed an opaque type? Was browsing some other language standard libraries and see that it's common to allow the backing PRNG to be swapped out, and from my understanding different algorithms might use different size seeds, not always U32. Maybe each seed implementation could provide some kind of init function that takes the specifically sized initial backing integer as an arg. It seems like a Random.Seed could be anything that implements an init function and a step or next function for progressing the seed forward, then the rest of the Random API could shape that generated value into the desired type/range. Zig seems to require each backing PRNG to provide a fill function that fills an arbitrarily sized buffer with random bytes, I guess because each seed's next function will generate varying sized values depending on the PRNG implementation, and we need an interface with a consistent return type regardless of PRNG backing state size.

2) As far as threading the seed around when generating values I had luck using a var declaration for the seed and reassigning it with tuple destructuring from the random generation functions, so for example:

var $rand_seed = Random.Seed.init(0)
(x, $rand_seed) = Random.u32_range(1, 6).gen($rand_seed)
(y, $rand_seed) = Random.u32_range(1, 6).gen($rand_seed)

Do people think the above destructuring looks weird or would be confusing?
I see that the current api uses a generic Generation(value) which is an alias for a record with { value : value, state : State }, but it does require the seed threading order to be maintained manually if lines get reordered etc. So I was looking at using a convention of Generator(value) : Seed -> (value, Seed), and having the usage code above. Here's another example that shows a function that contains rng, it receives an input seed and returns an updated seed as part of its output:

grid_size = 20
Point : { x : I32, y : I32 }
get_random_point : Random.Seed -> (Point, Random.Seed)
get_random_point = |rand_seed| {
    var $rand_seed = rand_seed
    (x, $rand_seed) = Random.i32_range(0, grid_size).gen($rand_seed)
    (y, $rand_seed) = Random.i32_range(0, grid_size).gen($rand_seed)
    ({ x, y }, $rand_seed)
}

NOTE: something this simple could be implemented with the mapping/chaining utility functions from the Random package rather than making a custom get_random_point function, but imagine if there was more complex logic in here, or the function required more args than just a seed

There's a risk here of accidently using the stale rand_seed rather than $rand_seed, but it seems like any API where seeds are threaded around runs the risk of using stale seeds, and using the var $rand_seed approach at least reduces problems when reordering lines in usage code.

3) How should we name the functions for generating integer ranges and whether they're inclusive or exclusive ranges etc. Zig uses some of the following for its random API: uintRangeLessThan uintAtMost. I saw that Rust's API takes a single range as an argument, which I thought was really nice and concise because the exclusive/inclusive question is self evident and doesn't need to be in the function name:

let x = rng.gen_range(1..=6)
let y = rng.gen_range(1..7)

I don't know if this is doable with Roc ranges, the type system would need to enforce at compile-time that the range (which I think is an Iter(num)) has a known length for example. It seems that Rust has some type machinery that can distinguish between known-length ranges vs unknown-length (or possibly infinite) ranges.

Sorry for the brain dump, just wanted to get people's thoughts on the pros/cons of the above, am excited to work on implementing some of this!

view this post on Zulip Anton (Jul 03 2026 at 13:16):

Do people think the above destructuring looks weird or would be confusing?

Looks good

view this post on Zulip Jonathan (Jul 03 2026 at 14:33):

Austin Clements said:

So I was looking at using a convention of Generator(value) : Seed -> (value, Seed), and having the usage code above.

Is the switch to tuples so that you can destructure into a var? I just tested and was a bit surprised you couldn't do this with records:

… {
… var $v = 0
… {$v, other} = {v : 1, other : 2}
… $v
… }

-> Type Mismatch - expects record of type { $v: _field, other: _field2 }
I.e., pattern matching treated $v in the punned record as a distinct name to v.

Strangely, this works:

» {
… var $v = 0
… {$v, other} = {$v: 1, other: 2}
… $v
… }
1.0

I.e., it is legal to use $v as a record field name, and then this matches with the $v var. This seems like a bug...?

view this post on Zulip Austin Clements (Jul 03 2026 at 14:51):

Right I’d need to try it I’m on mobile now, but I think you can rename a record field as you destructure it:

 {v: $v, other} = {v : 1, other : 2}

Meaning destructure the v field but actually assign it to $v (or whatever name you want)
I’m not well versed but I think the idea of the dollar sign is to know at a glance from any line that this is a var so probably makes sense that you couldn’t use it as a field name. So this could work with the random generator returning a record rather than a tuple, it could be a bit more noisy I guess? Also one of my concerns with tuples was that it’s easier to destructure them in the wrong order cause everything is just positional rather than named, but one benefit of making the returned Random.Seed be its own type rather than a U32 is you’re more likely to get a compile error when you destructure the tuple in the wrong order

view this post on Zulip Jonathan (Jul 03 2026 at 15:02):

Austin Clements said:

but imagine if there was more complex logic in here, or the function required more args than just a seed

I might be a bit beside the point, but I think you can reduce some of the threading here if you use record builder syntax. You can still parse in your arguments and return the generator which does the threading for you.

Point : { x : I32, y : I32 }
random_point_gen : U32, U32-> Generator(Point)
random_point_gen = |x_size, y_size| {
  {
    x: Random.i32_range(0, x_size),
    y: Random.i32_range(0, y_size)
  }.Random
}
Random.list(random_point_gen(11, 13), 17) # List of 17 points in 11x13 grid

Austin Clements said:

So this could work with the random generator returning a record rather than a tuple, it could be a bit more noisy I guess?

Agree a bit more noisy if you have to do that, but I was more surprised that it was legal to construct a record in the first place like so (probably needs a separate topic, sorry!)

» my_record = {$a : 1}
assigned `my_record`
» my_record.$a
## Parse error - please check your syntax
» my_record.a
## Type error - maybe "a" should be "$a"

Austin Clements said:

but one benefit of making the returned Random.Seed be its own type rather than a U32 is you’re more likely to get a compile error when you destructure the tuple in the wrong order

I think currently a Generator returns a Generation when run, and a Generation is an alias for {value : value, state : State}, for which State is an opaque type (containing the U32). Within State you could hold the seed, init and step functions I think as you say.

view this post on Zulip Austin Clements (Jul 03 2026 at 15:38):

Good point about the dollar field even being allowed in the first place! And also using the record builder syntax makes a lot of sense, that looks good. Also yeah looks like I was completely wrong about the internal representation of State being exposed to the user lol. But yeah I guess given you're in a situation where you can't cleanly use map chain or list etc on a generator and need to thread the seed yourself, I think I prefer

(x, $rand_state) = Random.i32_range(0, 10).gen($rand_state)

over

{ value: x, state: $rand_state } = Random.i32_range(0, 10).gen($rand_state)

or as in the threading example on roc-random

x = Random.i32_range(0, 10).gen(seed)
# now we need to use x.value to access the value and it also might not be clear from the
# name that x contains the most up-to-date prng state in one of its fields

but maybe it's not that consequential. Also realizing yeah rand_state or prng would be a better naming convention than rand_seed? This stuff is new to me, I see that the prng state holds more than just a seed

view this post on Zulip Austin Clements (Jul 03 2026 at 16:14):

Regarding using a number range as an argument for one of these random functions, I saw talk of ideally being able to pattern match on a range, I wonder does that mean the type of 1..=6 is something different than just Iter(num) and could be used here? Or maybe the pattern matching part would need to be some special case in the compiler that’s not exposed to users? Talking here about being able to make a Generator with Random.u32(1..=6)

view this post on Zulip Austin Clements (Jul 10 2026 at 19:57):

I made a PR to remove the modulo bias with bounded numbers in roc-random, I'm new to this stuff but based it on the resources at pcg-random.org
Wanted to share this, I made two scatter plots one with the new algorithm and one with the old biased algorithm, thought it was neat how you can see the repeating patterns visually in the biased one (warning not easy on the eyes)

Unbiased:
output.png

Biased:
outputbiased.png

view this post on Zulip Luke Boswell (Jul 10 2026 at 20:00):

I can take a look at that PR later :smile:

view this post on Zulip Luke Boswell (Jul 11 2026 at 02:47):

@Austin Clements I may have gotten carried away and also added a python oracle to generate thousands of spec tests and validate the implementation.

view this post on Zulip Luke Boswell (Jul 11 2026 at 02:52):

I think we're happy to land that and cut a new release, I will wait until you have had a change to respond.

view this post on Zulip Austin Clements (Jul 11 2026 at 03:30):

Oh wow THANK YOU cause I wasn’t sure how to find confidence in the code, go ahead with whatever you wanna do! Also I read about testing prngs with “known answer tests” and there were some short ones in the official PCG implementation, thought it could be good to add at some point if you want to check compliance with their implementation (BUT I dont think I saw any of their tests using signed integers and there seems to be gray area about how to do that unsigned to sign conversion)

view this post on Zulip Austin Clements (Jul 11 2026 at 15:19):

Also realizing maybe I should have left the example files to use the most recent release rather than main. Just now seeing the wisdom in keeping those stable, if that’s the preference I can go ahead and revert the changes to examples/ :+1:

view this post on Zulip Anton (Jul 11 2026 at 15:34):

Our nightly releases are right behind main: https://github.com/roc-lang/nightlies

view this post on Zulip Anton (Jul 11 2026 at 15:34):

That's probably the recommended target.

view this post on Zulip Austin Clements (Jul 11 2026 at 21:05):

@Luke Boswell Actually before you tag a release, I did find a couple of flaws in the backing generator implementation, a couple of shift arguments were swapped in the wrong order, and the code to initialize a seed didn't match the official implementation. I modified it and now the first hundred U32s generated align with the ones generated from the c implementation at https://github.com/imneme/pcg-c I'll probably do a separate PR for that and add a test checking against the first 20 or so values generated from the c version. This also might be a concern with the Python oracle which is currently mirroring the faulty PCG implementation I think, it might be good to hold off on the oracle so we don't get boxed into one approach yet, there seem to be many ways to set up the backing generator and that question might not be settled yet

view this post on Zulip Luke Boswell (Jul 11 2026 at 21:13):

I feel like we take our time on this PR and get it to a point we are happy with it. I'm not attached to the python thing if you wanted to remove or change it.

view this post on Zulip Austin Clements (Jul 16 2026 at 16:36):

Ok I added fixes to the backing pcg algorithm and some bigger tests that came straight from https://github.com/imneme/pcg-c and those are passing so I’m pretty confident that it’s compliant with the spec. Think this could be a good candidate for a release if you want to check it out at some point @Luke Boswell, thanks! No public API changes in this one

view this post on Zulip Luke Boswell (Jul 17 2026 at 03:13):

I'll try and cut a new release, I noticed the docs are borked so I'll look into that too

view this post on Zulip Luke Boswell (Jul 17 2026 at 03:55):

Here you go https://github.com/kili-ilo/roc-random/releases/tag/0.7.0

view this post on Zulip Austin Clements (Jul 17 2026 at 04:01):

Agg sorry about the docs forgot to check that, thanks for putting the time in!

view this post on Zulip Luke Boswell (Jul 17 2026 at 04:02):

I didn't mean the things you contributed... just the CI workflows. It turns out the front GH page hardcodes a specific release version, so easy fix

view this post on Zulip Luke Boswell (Jul 17 2026 at 04:02):

I also wanted an excuse to use the roc-lang/release-package GH actions, I've been trying to standardize all the packages I tend to work with around that.


Last updated: Jul 23 2026 at 13:15 UTC