how do i sequence multiple Stdout.line programmably? e.g. print a list of names with Stdout.line "hello \(name)"
. IIUC, backpassing is still callback and can only sequence pre-defined effects
Ok. Here is what I made...is there a better way?
Task.loop 0 \i ->
if i < List.len names then
_ <- Stdout.line "hello \(List.get names i |> Result.withDefault "Unwrap")" |> Task.await
Task.ok (Step (i + 1))
else
Task.ok (Done {})
I would do it like this:
names = ["a", "b", "c"]
printNames =
prevTask, name <- List.walk names (Task.ok {})
_ <- prevTask |> Task.await
Stdout.line "Next name was: \(name)"
_ <- printNames |> Task.await
Stdout.line "All done!"
Task.loop
also works, but I would use List.get
directly and avoid the withDefault
. Something like:
Task.loop 0 \i ->
when List.get names i is
Ok name ->
_ <- Stdout.line "hello \(name)" |> Task.await
Task.ok (Step (i + 1))
Err _ ->
Task.ok (Done {})
once we have Task
as a builtin, I like the idea of having helpers for that List.walk
version, e.g.
List.forEach : List elem, state, (state, elem -> Task state err) -> Task state err
Thanks Brendan! I was originally expecting of the former one (but missed a few bits)
and if any of them errors, the whole thing errors
Who doesn’t like Monad
Richard Feldman said:
once we have
Task
as a builtin
I can't remember if it was an episode of your podcast or the Roc documentation, but I thought Task
wasn't a builtin by design. Is the plan that there's a standard Task
interface which the platform authors must implement? Or rather, is there a feature request / issue I can find to learn more?
So the individual Task
s will always be implemented by a platform, but the actual wrapper that deal with success, failure, and how exactly data is exposed to the host will be changed to be a builtin.
The main reasons are:
https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/Task.20as.20builtin/near/363187595
Also the design proposal may be of interest https://github.com/lukewilliamboswell/roc-awesome?tab=readme-ov-file#task-as-builtin
Brendan Hansknecht said:
The main reasons are:
- We want to change to an effect interpreting state machine
- Certain functions we want Tasks to be able to support are impossible to define within roc itself. So we need some compiler/builtin magic.
Luke Boswell said:
Also the design proposal may be of interest https://github.com/lukewilliamboswell/roc-awesome?tab=readme-ov-file#task-as-builtin
Thanks guys that's exactly what I was looking for!
Brendan Hansknecht said:
The main reasons are:
- We want to change to an effect interpreting state machine
- Certain functions we want Tasks to be able to support are impossible to define within roc itself. So we need some compiler/builtin magic.
Off-topic, but I wonder how Task
s are currently being represented and interpreted by the platform? Is there a document I can read or term I can google to learn more about this topic?
Currently, roc kinda manually generates a bunch of glue that is essentially a linearized version of the program where roc has all of the control and the platform has none.
As a result, the platforms can't really do anything async or otherwise decide when/how roc executes.
Ah, gotcha! Thanks
Last updated: Jul 05 2025 at 12:14 UTC