Stream: ideas

Topic: Applicative Result


view this post on Zulip Luke Boswell (Jun 10 2023 at 02:00):

Luke Boswell said:

Ok, I think this is really cool. It also works with Result :smiley:

% roc run Experiments/Applicative.roc
Insufficient fruit available

app "applicative"
    packages {
        pf: "https://github.com/roc-lang/basic-cli/releases/download/0.3.2/tE4xS_zLdmmxmHwHih9kHWQ7fsXtJr7W7h3425-eZFk.tar.br",
    }
    imports [
        pf.Stdout,
    ]
    provides [main] to pf

main =

    myrecord : Result { apples : List Str, oranges : List Str } [LackOfFruit]
    myrecord = Ok {
        apples: <- getFruit Apples |> apply,
        oranges: <- getFruit Oranges |> apply,
    }

    when myrecord is
        Ok {apples,oranges} ->
            "Apples: "
            |> Str.concat (Str.joinWith apples ", ")
            |> Str.concat "\n"
            |> Str.concat "Oranges: "
            |> Str.concat (Str.joinWith oranges ", ")
            |> Stdout.line
        Err LackOfFruit ->
            Stdout.line "Insufficient fruit available"

getFruit : [Apples, Oranges] -> Result (List Str) [LackOfFruit]
getFruit = \request ->
    when request is
        Apples -> Ok ["Granny Smith", "Pink Lady", "Golden Delicious"]
        # Oranges -> Ok ["Navel", "Blood Orange", "Clementine"]
        Oranges -> Err LackOfFruit

apply : Result a err -> (Result (a -> b) err -> Result b err)
apply = \first -> \second ->
    when second is
        Ok f -> Result.map first f
        Err err -> Err err

view this post on Zulip Luke Boswell (Jun 10 2023 at 02:00):

Richard Feldman said:

Luke Boswell said:

myrecord : Result { apples : List Str, oranges : List Str } [LackOfFruit]
myrecord = Ok {
    apples: <- getFruit Apples |> apply,
    oranges: <- getFruit Oranges |> apply,
}

Interesting - I never even considered this usage!

When you're building a record anyway, it's a more concise alternative to Result.try and backpassing:

myrecord : Result { apples : List Str, oranges : List Str } [LackOfFruit]
myrecord =
    apples <- getFruit Apples |> Result.try,
    oranges <- getFruit Oranges |> Result.try,

    Ok { apples, oranges }

view this post on Zulip Luke Boswell (Jun 10 2023 at 02:01):

Idea for discussion -> should we have a Result.apply or Result.batch function?

view this post on Zulip Richard Feldman (Jun 10 2023 at 02:07):

personally I'm not a big fan of the names apply or batch for this case

view this post on Zulip Richard Feldman (Jun 10 2023 at 02:07):

myrecord : Result { apples : List Str, oranges : List Str } [LackOfFruit]
myrecord = Ok {
    apples: <- getFruit Apples |> apply,
    oranges: <- getFruit Oranges |> apply,
}

like what does "apply" really mean here?

view this post on Zulip Richard Feldman (Jun 10 2023 at 02:08):

try would be a fine name if it weren't already taken :sweat_smile:

view this post on Zulip Ed Kelly (Jun 10 2023 at 07:53):

Agreed - I mean, apples are definitely apply, but oranges aren't very apply.


Last updated: Jun 16 2026 at 16:19 UTC