Stream: API design

Topic: Higher-order effectful builtins


view this post on Zulip Agus Zubiaga (Oct 30 2024 at 13:57):

We seemed to have reached the conclusion that even with loops, we still want to have effectful counterparts of have functions like List.walk. I was going to include that in the Purity Inference PR, but I think we should do that separately once we have come up with the right API.

Here's a starting point for the discussion.

walk

An effectful List.walk! function seem essential:

List.walk! : List elem, state, (state, elem => state) => state

...and if you're running effects, most times you probably want to stop when one fails, so we should probably also have:

List.walkTry! : List elem, state, (state, elem => Result state err) => Result state err

You can also use this to stop early even if something didn't go wrong which is useful.

What about walkBackwards, walkWithIndex, walkUntil, walkWithIndexUntl, walkFrom, walkFromUntil?

forEach

It's probably going to be common to have to run an effect for each element of a List, so we could have:

List.forEach! : List a, (a => {}) => {}

In practice, a lot of effectful functions in real platforms will return Result which you won't want to discard, so we probably also need:

List.forEachTry! : List a, (a => Result {} err) => Result {} err

view this post on Zulip Agus Zubiaga (Oct 30 2024 at 14:08):

map

Should we have List.map!? At first, I thought I wouldn't perform effects while mapping a List, but actually some effects would fit:

contents = List.map! filesToRead File.read!

but of course, File.read! would probably return a Result, so what you really want is List.mapTry! :smile:

view this post on Zulip Agus Zubiaga (Oct 30 2024 at 14:10):

Maybe we just need the _Try! versions to start?

view this post on Zulip Agus Zubiaga (Oct 30 2024 at 14:11):

If we did that, I would probably still keep the Try suffix in their names for consistency

view this post on Zulip Brendan Hansknecht (Oct 30 2024 at 14:39):

I honestly think we should start with only forEach and leave everything else to be standard recursive functions in userland until there is clear need and use cases

view this post on Zulip Brendan Hansknecht (Oct 30 2024 at 14:40):

Especially with the for loop proposal on the horizon which I think would remove most of the need for these functions

view this post on Zulip Agus Zubiaga (Oct 30 2024 at 15:03):

Do you mean forEachTry!?

view this post on Zulip Agus Zubiaga (Oct 30 2024 at 15:04):

I don’t expect forEach! to be very useful in platforms like basic-cli, but maybe it would be for things like roc-ray

view this post on Zulip Brendan Hansknecht (Oct 30 2024 at 15:34):

I personally have only had uses for forEach! so far

view this post on Zulip Brendan Hansknecht (Oct 30 2024 at 15:36):

Oh wait....I might have had errors and results.....so maybe I need the try version

view this post on Zulip Brendan Hansknecht (Oct 30 2024 at 15:37):

But yeah, would add both forEach variants as a starter.

view this post on Zulip Luke Boswell (Nov 09 2024 at 05:11):

I'd like to propose we add an Result.onErr! so we don't need to do things like this... unless I'm missing something about how this should work in a purity inference world.

main! = \{} ->
    when run! {} is
        Ok {} -> Ok {}
        Err err -> handleErr! err

view this post on Zulip Luke Boswell (Nov 09 2024 at 05:12):

main! = \{} ->
    run! {}
    |> Result.onErr! handleErr!

Last updated: Jul 06 2025 at 12:14 UTC