From cce57ea3c40f20b13430984c58c2fca36a506dee Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Thu, 18 Apr 2024 08:46:23 +1000 Subject: [PATCH 1/5] Add Task.result --- platform/Task.roc | 56 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/platform/Task.roc b/platform/Task.roc index 17ad12a..08d74b8 100644 --- a/platform/Task.roc +++ b/platform/Task.roc @@ -13,6 +13,7 @@ interface Task loop, fromResult, batch, + result, ] imports [Effect, InternalTask] @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -176,8 +177,8 @@ 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 @@ -185,16 +186,16 @@ mapErr = \task, transform -> ## 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 @@ -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 From bfcd5c3ddbab37971782af325014b40212be0b6d Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Sun, 21 Apr 2024 13:54:14 +1000 Subject: [PATCH 2/5] add result test --- ci/all_tests.sh | 1 + ci/expect_scripts/result.exp | 22 ++++++++++++++++++++++ examples/result.roc | 23 +++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 ci/expect_scripts/result.exp create mode 100644 examples/result.roc diff --git a/ci/all_tests.sh b/ci/all_tests.sh index ef7e357..9cf9ca3 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -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 diff --git a/ci/expect_scripts/result.exp b/ci/expect_scripts/result.exp new file mode 100644 index 0000000..b22187e --- /dev/null +++ b/ci/expect_scripts/result.exp @@ -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 \ No newline at end of file diff --git a/examples/result.roc b/examples/result.roc new file mode 100644 index 0000000..82ff8d4 --- /dev/null +++ b/examples/result.roc @@ -0,0 +1,23 @@ +app "result" + packages { pf: "../platform/main.roc" } + imports [ + pf.Task.{ Task }, + pf.Http.{ Request, Response }, + ] + provides [main] to pf + +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: 200, headers: [], body: Str.toUtf8 "ERROR" } + +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 \ No newline at end of file From 985db65473dfc4d62e6b3af67d2f593cf3b3070a Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:30:47 +0200 Subject: [PATCH 3/5] nix flake lock update --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 4621de0..7765860 100644 --- a/flake.lock +++ b/flake.lock @@ -102,11 +102,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1713180354, - "narHash": "sha256-laLEu12yP0gD+dqqT3OClH6LLD1uAtPiyto0y5D7xus=", + "lastModified": 1713751891, + "narHash": "sha256-IuCUqK6N5P/uClhmAM/Z+JNNvrTpSSe6nkC7dxXMikI=", "owner": "roc-lang", "repo": "roc", - "rev": "a0cf09f9802eb07a05a73155729e370ebf3a9e9a", + "rev": "e4713ce2c5c07619e39e59fbfde29e9021cd78d1", "type": "github" }, "original": { @@ -161,11 +161,11 @@ ] }, "locked": { - "lastModified": 1712973993, - "narHash": "sha256-ZJxC6t2K0UAPW+lV+bJ+pAtwbn29eqZQzXLTG54oL+I=", + "lastModified": 1713752081, + "narHash": "sha256-x0QDETp7paa8qq+LX6191JwSq8abUFXCnKNulQ8L7ps=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "a497535d074432133b683dda3a1faa8c8ab587ad", + "rev": "606c0ecb23c676c444a0b026eecf800d5bd5fec2", "type": "github" }, "original": { From e3d0f04b1691878f9154fefd6c39690fd5da91ce Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 22 Apr 2024 16:10:31 +0200 Subject: [PATCH 4/5] minor improvements --- examples/result.roc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/result.roc b/examples/result.roc index 82ff8d4..ed3a109 100644 --- a/examples/result.roc +++ b/examples/result.roc @@ -6,12 +6,16 @@ app "result" ] 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: 200, headers: [], body: Str.toUtf8 "ERROR" } + Err IOError -> Task.ok { status: 500, headers: [], body: Str.toUtf8 "ERROR: IoError when executing checkFile." } checkFile : Str -> Task [Good, Bad] [IOError] checkFile = \str -> @@ -20,4 +24,4 @@ checkFile = \str -> else if str == "bad" then Task.ok Bad else - Task.err IOError \ No newline at end of file + Task.err IOError From 4dd95a680efa96d0d5bea0447eec5d8846871786 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 22 Apr 2024 16:11:12 +0200 Subject: [PATCH 5/5] Added colon --- platform/Task.roc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/Task.roc b/platform/Task.roc index 08d74b8..c51ef0c 100644 --- a/platform/Task.roc +++ b/platform/Task.roc @@ -222,7 +222,7 @@ batch = \current -> \next -> ## 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 +## This is useful when chaining tasks using the `!` suffix. For example: ## ## ``` ## # Path.roc