Skip to content

Commit

Permalink
Merge pull request #47 from roc-lang/task-result
Browse files Browse the repository at this point in the history
Add `Task.result`
  • Loading branch information
Anton-4 committed Apr 22, 2024
2 parents 75d5199 + 4dd95a6 commit 293a73f
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 21 deletions.
1 change: 1 addition & 0 deletions ci/all_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ expect ci/expect_scripts/error-handling.exp
expect ci/expect_scripts/file.exp
expect ci/expect_scripts/hello-web.exp
expect ci/expect_scripts/sleep.exp
expect ci/expect_scripts/result.exp

# test building website
$ROC docs platform/main.roc
22 changes: 22 additions & 0 deletions ci/expect_scripts/result.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/expect

# uncomment line below for debugging
# exp_internal 1

set timeout 7

spawn $env(EXAMPLES_DIR)result

expect "Listening on localhost port 8000\r\n" {
set curlOutput [exec curl -sS localhost:8000 -d ""]

if {$curlOutput eq "GOOD"} {
exit 0
} else {
puts "Error: curl output was different than expected: $curlOutput"
exit 1
}
}

puts stderr "\nError: output was different than expected."
exit 1
27 changes: 27 additions & 0 deletions examples/result.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
app "result"
packages { pf: "../platform/main.roc" }
imports [
pf.Task.{ Task },
pf.Http.{ Request, Response },
]
provides [main] to pf

# This example demonstrates the use of `Task.result`.
# It transforms a task that can either succeed with `ok`, or fail with `err`, into
# a task that succeeds with `Result ok err`.

main : Request -> Task Response []
main = \_ ->
when checkFile "good" |> Task.result! is
Ok Good -> Task.ok { status: 200, headers: [], body: Str.toUtf8 "GOOD" }
Ok Bad -> Task.ok { status: 200, headers: [], body: Str.toUtf8 "BAD" }
Err IOError -> Task.ok { status: 500, headers: [], body: Str.toUtf8 "ERROR: IoError when executing checkFile." }

checkFile : Str -> Task [Good, Bad] [IOError]
checkFile = \str ->
if str == "good" then
Task.ok Good
else if str == "bad" then
Task.ok Bad
else
Task.err IOError
12 changes: 6 additions & 6 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 41 additions & 15 deletions platform/Task.roc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface Task
loop,
fromResult,
batch,
result,
]
imports [Effect, InternalTask]

Expand Down Expand Up @@ -45,7 +46,7 @@ loop = \state, step ->
\res ->
when res is
Ok (Step newState) -> Step newState
Ok (Done result) -> Done (Ok result)
Ok (Done newResult) -> Done (Ok newResult)
Err e -> Done (Err e)

Effect.loop state looper
Expand Down Expand Up @@ -100,8 +101,8 @@ attempt : Task a b, (Result a b -> Task c d) -> Task c d
attempt = \task, transform ->
effect = Effect.after
(InternalTask.toEffect task)
\result ->
when result is
\res ->
when res is
Ok a -> transform (Ok a) |> InternalTask.toEffect
Err b -> transform (Err b) |> InternalTask.toEffect

Expand All @@ -122,8 +123,8 @@ await : Task a b, (a -> Task c b) -> Task c b
await = \task, transform ->
effect = Effect.after
(InternalTask.toEffect task)
\result ->
when result is
\res ->
when res is
Ok a -> transform a |> InternalTask.toEffect
Err b -> err b |> InternalTask.toEffect

Expand All @@ -140,8 +141,8 @@ onErr : Task a b, (b -> Task a c) -> Task a c
onErr = \task, transform ->
effect = Effect.after
(InternalTask.toEffect task)
\result ->
when result is
\res ->
when res is
Ok a -> ok a |> InternalTask.toEffect
Err b -> transform b |> InternalTask.toEffect

Expand All @@ -158,8 +159,8 @@ map : Task a c, (a -> b) -> Task b c
map = \task, transform ->
effect = Effect.after
(InternalTask.toEffect task)
\result ->
when result is
\res ->
when res is
Ok a -> ok (transform a) |> InternalTask.toEffect
Err b -> err b |> InternalTask.toEffect

Expand All @@ -176,25 +177,25 @@ mapErr : Task c a, (a -> b) -> Task c b
mapErr = \task, transform ->
effect = Effect.after
(InternalTask.toEffect task)
\result ->
when result is
\res ->
when res is
Ok c -> ok c |> InternalTask.toEffect
Err a -> err (transform a) |> InternalTask.toEffect

InternalTask.fromEffect effect

## Use a Result among other Tasks by converting it into a [Task].
fromResult : Result a b -> Task a b
fromResult = \result ->
when result is
fromResult = \res ->
when res is
Ok a -> ok a
Err b -> err b

## Shorthand for calling [Task.fromResult] on a [Result], and then
## [Task.await] on that [Task].
awaitResult : Result a err, (a -> Task c err) -> Task c err
awaitResult = \result, transform ->
when result is
awaitResult = \res, transform ->
when res is
Ok a -> transform a
Err b -> err b

Expand All @@ -217,3 +218,28 @@ batch = \current -> \next ->
f <- next |> await

map current f

## Transform a task that can either succeed with `ok`, or fail with `err`, into
## a task that succeeds with `Result ok err`.
##
## This is useful when chaining tasks using the `!` suffix. For example:
##
## ```
## # Path.roc
## checkFile : Str -> Task [Good, Bad] [IOError]
##
## # main.roc
## when checkFile "/usr/local/bin/roc" |> Task.result! is
## Ok Good -> "..."
## Ok Bad -> "..."
## Err IOError -> "..."
## ```
##
result : Task ok err -> Task (Result ok err) *
result = \task ->
effect =
Effect.after
(InternalTask.toEffect task)
\res -> res |> ok |> InternalTask.toEffect

InternalTask.fromEffect effect

0 comments on commit 293a73f

Please sign in to comment.