Stream: beginners

Topic: how to sequence side effects


view this post on Zulip Steven Chen (Dec 12 2023 at 00:38):

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

view this post on Zulip Steven Chen (Dec 12 2023 at 02:07):

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 {})

view this post on Zulip Brendan Hansknecht (Dec 12 2023 at 02:17):

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!"

view this post on Zulip Brendan Hansknecht (Dec 12 2023 at 02:20):

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 {})

view this post on Zulip Richard Feldman (Dec 12 2023 at 02:34):

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

view this post on Zulip Steven Chen (Dec 12 2023 at 02:34):

Thanks Brendan! I was originally expecting of the former one (but missed a few bits)

view this post on Zulip Richard Feldman (Dec 12 2023 at 02:34):

and if any of them errors, the whole thing errors

view this post on Zulip Steven Chen (Dec 12 2023 at 02:36):

Who doesn’t like Monad

view this post on Zulip Fletch Canny (Dec 12 2023 at 03:56):

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?

view this post on Zulip Brendan Hansknecht (Dec 12 2023 at 04:14):

So the individual Tasks 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.

view this post on Zulip Brendan Hansknecht (Dec 12 2023 at 04:15):

The main reasons are:

  1. We want to change to an effect interpreting state machine
  2. Certain functions we want Tasks to be able to support are impossible to define within roc itself. So we need some compiler/builtin magic.

view this post on Zulip Brendan Hansknecht (Dec 12 2023 at 04:16):

https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/Task.20as.20builtin/near/363187595

view this post on Zulip Luke Boswell (Dec 12 2023 at 06:24):

Also the design proposal may be of interest https://github.com/lukewilliamboswell/roc-awesome?tab=readme-ov-file#task-as-builtin

view this post on Zulip Fletch Canny (Dec 12 2023 at 12:24):

Brendan Hansknecht said:

The main reasons are:

  1. We want to change to an effect interpreting state machine
  2. 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!

view this post on Zulip Sven van Caem (Dec 12 2023 at 19:58):

Brendan Hansknecht said:

The main reasons are:

  1. We want to change to an effect interpreting state machine
  2. 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 Tasks 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?

view this post on Zulip Brendan Hansknecht (Dec 12 2023 at 20:50):

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.

view this post on Zulip Brendan Hansknecht (Dec 12 2023 at 20:51):

As a result, the platforms can't really do anything async or otherwise decide when/how roc executes.

view this post on Zulip Sven van Caem (Dec 13 2023 at 21:11):

Ah, gotcha! Thanks


Last updated: Jul 05 2025 at 12:14 UTC