Hi, I'm currently streaming my daily solves of AoC on Twitch.
Since I'm new to functional programming and Roc I'd love if some more experienced people would join my chat and provide feedback and improvements on the frequently horrible code I write :D
Beginners are always welcome too obviously.
You can find it on https://twitch.tv/ScallyGamesDev
What time do you normally stream?
Woah, there's ads on Twitch :grimacing: -- I hope they don't interrupt streams
Just listening to Day 10 now... :smiley:
@Scally mind if I drop some ideas for you in here?
Checkout List.keepOks -- I like to use that sometimes for AoC for quick and dirty parsing the lines where I have a Result
Brendan Hansknecht said:
What time do you normally stream?
Well... :sweat_smile: that unfortunately varies widely.
Usually around afternoon/evening CET but also sometimes late night or early morning xD
I'd say probably easiest to follow to get notified when I go live :thinking:
Alright, I'll give you a sub
They sadly do @Luke Boswell :| Also you sadly can't fully turn them off as a streamer. I'd honestly recommend using adblocks
Follow is good enough and free, sub is appreciated nontheless :D
Also thanks for checking out the VOD
Apparently I'm a Twitch noob... I'm the guy that catches streams people have uploaded to YT
Luke Boswell said:
Scally mind if I drop some ideas for you in here?
Sure, I'd love that
I've used List.keepOks a bunch already but yes, managing errors and results is one of my biggest troubles still.
Can you tell me why List.keeppOks takes a function as argument instead of just working on a list of results? It seems somewhat annoying. Or is there some better way to include it in a pipeline than going
somethingThatGeneratesListOfResults |> List.keepOks \x -> x
Yeah, youtube subscribes are twitch follows, twitch subscribes are paid support that unlocks emotes and some other stuff.
To me the youtube subscribe term always felt weird because it seemed to me like it was paid.
Not to confuse things further, but I pay for YT so I don't have ads
Also something that's been repeatedly annoying to me is Results after I know that it won't fail.
Something like
# already did bound check
List.get list 0
What I usually do is pipe it into Result.withDefault 0
or something alike, knowing it will never happen, but it always feels really bad
I sometimes throw a quick and dirty one of these in and use that for AoC
unwrap : Result ok err -> ok
unwrap = \result ->
when result is
Ok value -> value
Err _ -> crash "expected Ok"
Luke Boswell said:
Just listening to Day 10 now... :smiley:
Btw, AoC 10 has probably been one of my better days :laughter_tears:
Some days were that terrible that I did a second stream for redemption trying to improve on my solution xD
I think that is fine for these kind of programs where we are just slapping code together and not too concerned about errors
Okay, I was wondering because some other languages have unwrap (I think I know it from Rust) but Roc doesn't
As I've learnt more though, I've found my need for that has dropped off dramatically though, so it's definitely something I've gotten more comfortable with handling the errors and passing them up through the program
Using ?
makes like much easier too
I was assuming that it's something that would go away as I got better but so far I haven't found any great solutions.
My assumption is that Result.try or the new try keyword will help but I haven't quite figured out how to properly use that.
Usually any attempts to use try results in compiler errors because of incorrect arguments to something xD
part1 : Str -> Result Str _
part1 = \input ->
tests : List Test
tests = parseStr? (sepBy parse_test (codeunit '\n')) (Str.trim input)
...
The key thing in this example is that I use a _
to infer the error type
So I don't care about the errors from my parseStr
function.. that just gets passed up the chain
So try
and ?
are implemented identically under the hood now. In the long term I suspect ?
will fit nicer with the parens and commas design that's been kicking around. But for now we have both.
Interesting, I'll have to look into the Str -> Result Str _
tomorrow, bubbling up errors is kind of what I wanted, just never seemed to get it to work.
Initially it was also really confusing because iirc some APIs actually throw errors instead of returning results and those errors just stop execution of the function and in the end crash the program.
In many cases I wished I'd just get a crash instead of a Result. Is there some way to convert an Err to a crash? I assume the custom unwrap function you've posted above?
I assume the custom unwrap function you've posted above?
Yes, this is the only way
some APIs actually throw errors instead of returning results
This should only be for things that cannot be handled in any sensible way but crashing
Ah, I think it was mostly for Tasks
I remember some videos / talks by Richard where he showed off some basic programs and it was basically only crashes, no working with results there.
I'm currently listening to you explaining why AoC isn't well suited for FP :smiley:
There was some really neat Haskell implementation for today's task by someone in my chat
https://github.com/Andriamanitra/adventofcode2024/blob/main/day10/solution.hs
Lol, looking at it rn
Jup, that's the one
Today and the one with the bridge and doing math operations on a list of operands was really nice with FP
My Roc tends to be really verbose... but I don't mind it like that.
I tend to write smaller parts and then use expects
to test my assumptions at each point as I go.
Others seem to be able to keep a whole algorithm in their head and write something correct using much less code than me.
I just recently started breaking things up more and more since doing long function chain would result in the editor underlining like 12 lines of code saying there was something wrong with some type at some point in those lines :sweat_smile:
Also I had some really bad issues with some stupid single value or operation incorrectly inferring some type which then messed up some type signature way up the chain
I really like working with the compiler and using type annotations to help me "think" about the algorithm. Like I can "pin" the type at a point and get instant feedback if the compiler agrees with me or not.
Like somewhere in the function chain some U64 + Num (but actually I64 or similar) operation which then suddenly changes the entire type of the Num to U64 which then bubbles up instead of it telling me I couldn't do addition between unsigned and signed int.
Creating smaller functions and adding explicit type annotations really helped on that
Yeah, I think I talked about it on today's stream that I really started to like starting to write a function in terms of it's signature
Yeah, I often start with types for anything vaguely complex
Here's an example... I'm even doing it in the middle of a function.
part1 : Str -> Result Str _
part1 = \input ->
tests : List Test
tests = parseStr? (sepBy parse_test (codeunit '\n')) (Str.trim input)
valid_tests : List Test
valid_tests =
List.keepIf tests \test ->
k = 2 # Add, Mul
find_first_valid_ast test k |> Result.isOk
valid_tests
|> List.map .test_value
|> List.sum
|> Num.toStr
|> Ok
Usually I'm writing that as I think through the algorithm, so even though it's more verbose it somehow saves me wall time, because I get to a correct solution faster.
Yeah, I've started doing some of that
Btw, do you have any recommendations on a function lacking a return or having 2 returned values breaking all of intellisense and type checking? :sweat_smile:
I'm not sure I've seen this issue before
Oh, like if it can't parse the file it prevents type checking?
I think @Joshua Warner or @Sam Mohr were working on something for a more tolerant parser
Actually... that might be what is going on with this issue https://github.com/roc-lang/roc/issues/7332 I just reported from your comments on stream. I asked Josh and he said it looks like it may be language server related
Yeah, running roc check
gives use the expected error report. So this is a language server thing.
Like something like
doSomething = \a ->
test = getSomething
# currently still working on this function
part1 -> \input
# ....
or
doSomething = \a ->
getSomething
a == 1
part1 -> \input
# ....
usually resulted in a general parser error and breaking all editor integration.
I think it's been more of an issue with Zed than in VSCode and especially annoying because the error message says something like
Error parsing
somewhere around here
========
doSomething = \a ->
[120] test = getSomething
^
========
so it seems to know the line number but it only shows the error on line 1 on the app keyword (I guess character 1 of the file).
Luke Boswell said:
I think Joshua Warner or Sam Mohr were working on something for a more tolerant parser
yeah, exactly that.
I think earlier I saw something on a thread here about having to reload the Zed editor because it was breaking all the time.
Another thing I've found that saves a lot of pain, is actually parsing the input. So instead of leaving the "heights" as U8
, parsing that into Heights: [L1, L2, L3, ..]
for example. On the days when I don't use roc-parser
I tend to find at lesat two or three bugs where I simply just assume something obvious like forgetting that '9'
and 9
are different numbers :sweat_smile:
Hm... so parsing the integers into Tags? I've done that on the defragmentation task and it was quite nice (apart from sometimes being confused with the syntax of opaque types)
Clip on intellisense issues for reference: https://www.twitch.tv/scallygamesdev/clip/ComfortableTenuousSrirachaPJSalt-id4WvH-OQXEwCGcU
cc @Sam Mohr and @Joshua Warner who work on the parser.
I think it's a language server thing. @Eli Dowling said he'll have a look at it and scope (suss) it out.
Ah, sorry for wrong pings then.
Alg, I just wanted to let Sam and Josh know I'd had a quick chat to Eli
so it seems to know the line number but it only shows the error on line 1 on the app keyword (I guess character 1 of the file).
Can we do a quick change for this that underlines the entire file? I usually never notice the top error for a while and I continue thinking my code is all correct. It's easier to fix errors immediately.
I will try to fix it today @Anton if I can't get it solved I'll make a pr changing the default scope :)
Language server reports a lot of weird errors I don't see with roc check
, and it will stick around at the top of the file forever until you restart the LSP.
Language server reports a lot of weird errors I don't see with
roc check
That is strange, I don't think I've ever had that, do you have an example?
I've definitely had the lsp get into a nasty not dead not alive state before. Got a deadlock in there somewhere I guess. I'm not sure if we have a way of timing out when the compiler hangs. Which it does fairly often with recursive code.
Hanging -> in a when will do it for me pretty reliably
But I have a lot more feedback on language server when I have time to write it down
Last updated: Jul 06 2025 at 12:14 UTC