Day 5, part 1 and 2: https://github.com/ayazhafiz/roc-advent-of-code/blob/main/2021/day5.roc
I feel like this problem hit the limit of what the associativity-list implementation of Dict
in the standard library can do. I used @Brendan Hansknecht 's implementation here instead. I know there are more efficient ways to solve this problem, but this is probably a sign we should implement Hash
and a faster Dict implementation :sweat_smile:
I probably have a similar implementation, but I used our list based set in a way that it still worked for the problem....though it definitely took a bit on part 2: https://github.com/bhansconnect/roc-aoc-2021/tree/trunk/day5
Super inefficient, but I really like the solution after parsing: https://github.com/bhansconnect/roc-aoc-2021/blob/trunk/day5/part2.roc#L96
otherwise, wow, Roc makes parsing into ad-hoc representations so painless. Only define the type annotations you want, compose things easily without ceremony - the startup ergonomics are at least as nice as they are in Haskell, and definitely feel better in most cases
I definitely have to learn your parser stuff at some point. Until then...the world of Str.split
and hacks continues.
Set is smarter, I used Dict which ends up touching a lot more probably
Ah, that's definitely true.
hopefully your U64FlatHashDict
can carry us, as long as we need it, until we implement one for the stdlib
If you help me add Hash
, I should be able to upgrade the standard library dict and set. Though we do want to change a few things about my version to avoid ordering problems (should be done before merging) and hash flooding attacks (can be done after merging).
I really just don't know much about abilities, but once I see a dummy implementation and just need to fill in the bodies, I should be good.
opened #ideas > Hash ability to discuss. Happy to pair on the ability implementation once we get the base API sorted out, now that we have Encode/Decode in place you'll see that it's relatively straightforward
My day 5 part 1 is an abomination: https://github.com/shritesh/advent/blob/main/2021/5.roc
I couldn't figure out how to use the aforementioned parser in the stdlib (including two packages crashes the compiler?) so I hand rolled my own state-machine based one. Also, I couldn't figure out an ergonomic way to essentially do List.update
so I've got a hackjob of List.replace
, List.set
and custom tag types to make it work, which is probably why the code runs dead slow.
The issue is likely not truely your fault. Roc has some shape edges around uniqueness and copying. I am betting that you are copying your 1ish MB list many many times.
I am gonna test an try to figure if uniqueness is the issue.
Yeah, this is 100% roc uniqueness sharp edge leading to tons of copying.
Try changing cover to this:
cover = \{width, height, data}, x, y ->
index = width * x + y
when List.replace data index One is
{ value: None, list } -> { width, height, data: list }
{ value: One, list } -> { width, height, data: List.set list index TwoOrMore }
{ value: TwoOrMore, list } -> { width, height, data: List.set list index TwoOrMore }
The problem is that you were keep a reference to the grid because it was used after the List.replace
statement in the when clause. This meant that every call to List.replace
had to completely clone the list. This allocated about 1MB for every point in every line.
Yup. Much faster. Thanks
Part 2 is done: https://github.com/shritesh/advent/blob/main/2021/5.roc
List.range
is broken in Roc. List.range 1 1 == List.range 1 2 == [1]
.
@Brendan Hansknecht 's solution helped in figuring that out.
Filed an issue about it: https://github.com/roc-lang/roc/issues/4196
:+1: thanks @Shritesh Bhattarai :)
Hi, here's my solution for part2 https://github.com/ghigt/advent-of-code/blob/main/roc/day-5/part2.roc
My algorithm is SOO slow, 4min on my M1 :(
99% of it is spent on this function to look for the duplications:
seeDuplicate : List Coord -> Set Coord
seeDuplicate = \list ->
List.walk list { s: Set.empty, d: Set.empty } (\{s, d}, c ->
if Set.contains s c then
{ d: Set.insert d c, s }
else
{ s: Set.insert s c, d }
)
|> .d
Tried several other implementations with only one Set
and Tag
but it was even worse
Currently sets are list based instead of hash set based. So contains and insert both scan the entire list doing comparisons.
We just added the Hash
ability. Soon, i will port over a Hash based dictionary (and set). That should greatly help here.
Also, i think lists currently grow by 1 element instead of 1.5 to 2x. So every time you insert, the list has to be reallocated and all bytes copied.
In other words, probably more a Roc maturity problem than a real problem with your code.
Ok, a strategy like in Go which grows the slice capacity by 2x if append
needs it
I should look at the implementation of List
, I naively thought it was a rust Vec
which then grew its capacity with the rust strategy
I think we would prefer 1.5x more than 2x. The issue with 2x is that it can never reuse memory. Your new list is always large enough that it can't fit in the sum of all previous memory locations it occupied even if they are continuous. As such, the number at most can be the golden ratio.
But yeah, should be a simple addition if you want to try and fix it. (assuming it hasn't already been done)
Yeah, looks like this still needs to be done. Might require changes in a few different functions (probably funneling them all through list a single growth function)
oh, I'm a "read-only" source code developer on Roc for now, hope to be able to help in a near future when I will have a better understanding of what happens under the hood! :sweat_smile:
But having a look at all PR/docs since a couple of weeks now, it's a real pleasure to learn!
Ah, that's fine.
I'll add this and we can see if/how much it helps your example
Oh, actually in this case, I think you just needed the --optimize
flag. I just ran it on an M1 and it ran in 13s.
What does this flag do?
I think it requests LLVM to optimize for execution speed.
in general it tells the Roc compiler "spend time optimizing this program so that it will run faster (but take longer to build compared to normal)"
Last updated: Jul 06 2025 at 12:14 UTC