Task
Task ok err
A Task represents an effect; an interaction with state outside your Roc program, such as the terminal's standard output, or a file.
forever : Task a err -> Task * err
Run a task repeatedly, until it fails with err
. Note that this task does not return a success value.
loop : state, (state -> Task [ Step state, Done done ] err) -> Task done err
Run a task repeatedly, until it fails with err
or completes with done
.
sum = Task.loop! 0 \total -> numResult = Stdin.line |> Task.result! |> Result.try Str.toU64 when numResult is Ok num -> Task.ok (Step (total + num)) Err (StdinErr EndOfFile) -> Task.ok (Done total) Err InvalidNumStr -> Task.err NonNumberGiven
ok : a -> Task a *
Create a task that always succeeds with the value provided.
# Always succeeds with "Louis" getName : Task.Task Str * getName = Task.ok "Louis"
err : a -> Task * a
Create a task that always fails with the error provided.
# Always fails with the tag `CustomError Str` customError : Str -> Task.Task {} [CustomError Str] customError = \err -> Task.err (CustomError err)
attempt : Task a b, (Result a b -> Task c d) -> Task c d
Transform a given Task with a function that handles the success or error case and returns another task based on that. This is useful for chaining tasks together or performing error handling and recovery.
Consider the following task:
canFail : Task {} [Failure, AnotherFail, YetAnotherFail]
We can use attempt
to handle the failure cases using the following:
Task.attempt canFail \result -> when result is Ok Success -> Stdout.line "Success!" Err Failure -> Stdout.line "Oops, failed!" Err AnotherFail -> Stdout.line "Ooooops, another failure!" Err YetAnotherFail -> Stdout.line "Really big oooooops, yet again!"
Here we know that the canFail
task may fail, and so we use
Task.attempt
to convert the task to a Result
and then use pattern
matching to handle the success and possible failure cases.
await : Task a b, (a -> Task c b) -> Task c b
Take the success value from a given Task
and use that to generate a new Task
.
We can await
Task results with callbacks:
Task.await (Stdin.line "What's your name?") \name -> Stdout.line "Your name is: $(name)"
Or we can more succinctly use the !
bang operator, which desugars to await
:
name = Stdin.line! "What's your name?" Stdout.line "Your name is: $(name)"
onErr : Task a b, (b -> Task a c) -> Task a c
Take the error value from a given Task
and use that to generate a new Task
.
# Prints "Something went wrong!" to standard error if `canFail` fails. canFail |> Task.onErr \_ -> Stderr.line "Something went wrong!"
map : Task a c, (a -> b) -> Task b c
Transform the success value of a given Task
with a given function.
# Succeeds with a value of "Bonjour Louis!" Task.ok "Louis" |> Task.map (\name -> "Bonjour $(name)!")
mapErr : Task c a, (a -> b) -> Task c b
Transform the error value of a given Task
with a given function.
# Ignore the fail value, and map it to the tag `CustomError` canFail |> Task.mapErr \_ -> CustomError
fromResult : Result a b -> Task a b
Use a Result among other Tasks by converting it into a Task
.
batch : Task a c -> Task (a -> b) c -> Task b c
Apply a task to another task applicatively. This can be used with
ok
to build a Task
that returns a record.
The following example returns a Record with two fields, apples
and
oranges
, each of which is a List Str
. If it fails it returns the tag
NoFruitAvailable
.
getFruitBasket : Task { apples : List Str, oranges : List Str } [NoFruitAvailable] getFruitBasket = Task.ok { apples: <- getFruit Apples |> Task.batch, oranges: <- getFruit Oranges |> Task.batch, }
sequence : List (Task ok err) -> Task (List ok) err
Apply each task in a list sequentially, and return a list of the resulting values. Each task will be awaited before beginning the next task.
fetchAuthorTasks : List (Task Author [DbError]) getAuthors : Task (List Author) [DbError] getAuthors = Task.sequence fetchAuthorTasks
forEach : List a, (a -> Task {} b) -> Task {} b
Apply a task repeatedly for each item in a list
authors : List Author saveAuthor : Author -> Task {} [DbError] saveAuthors : Task (List Author) [DbError] saveAuthors = Task.forEach authors saveAuthor
result : Task ok err -> Task (Result ok err) *
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 -> "..."