interface InteractiveExample exposes [view] imports [pf.Html.{ pre, samp, div, text, a, class, p }, pf.Html.Attributes.{ class, role, href, id }] Section : [Desc (List Token) Str, Indent, Outdent, Newline] Token : [ Kw Str, Ident Str, Str Str, Num Str, Comment Str, Literal Str, ParensAround (List Token), Lambda (List Str), StrInterpolation Str Str Str, ] view : Html.Node view = output = sectionsToStr [ Desc [Comment "Click anything here to see an explanation.Tap anything here to\n# see an explanation."] "
Comments in Roc begin with a #
and go to the end of the line.
This defines main
, which is where our program will begin.
In Roc, all definitions are constant, so writing main =
again in the same scope would give an error.
This converts the string \"url.txt\"
into a Path
by passing it to Path.fromStr
.
Function arguments are separated with whitespace. Parentheses are only needed in nested function calls.
", Newline, Desc [Kw "|>", Ident "storeEmail"] "The pipe operator (|>
) is syntax sugar for passing the previous value to the next function in the \"pipeline.\"
This line takes the value that Path.fromStr \"url.txt\"
returns and passes it to storeEmail
.
The next |>
continues the pipeline.
If the task returned by the previous step in the pipeline fails, pass its error to handleErr
.
The pipeline essentially does this:
a = Path.fromStr \"url.txt\"\nb = storeEmail a\n\nTask.onErr b handleErr
It creates a Path
from a string, stores an email based on that path, and then does error handling.
This defines a function named storeEmail
. It takes one argument, named path
.
In Roc, functions are ordinary values, so we assign names to them using =
like with any other value.
The \\arg1, arg2 ->
syntax begins a function, and the part after ->
is the function's body.
This reads the contents of the file (as a UTF-8 string) into url
.
The <-
does backpassing, which is syntax sugar for defining a function. This line desugars to:
Task.await\n (File.readUtf8 path)\n \\url ->
The lines after this one form the body of the \\url ->
callback, which runs if the file read succeeds.
This fetches the contents of the URL and decodes them as JSON.
If the shape of the JSON isn't compatible with the type of user
(based on type inference), this will give a decoding error immediately.
As with all the other lines ending in |> Task.await
, if there's an error, nothing else in storeEmail
will be run, and handleErr
will end up handling the error.
The \\(user.name)
in this string literal will be replaced with the value in name
. This is string interpolation.
Note that this line doesn't end with |> Task.await
. Earlier lines needed that because they were I/O tasks, but this is a plain old definition, so there's no task to await.
This writes user.email
to the file, encoded as UTF-8.
We won't be using the output of writeUtf8
, so we name it _
. The special name _
is for when you don't want to use something.
You can name as many things as you like _
, but you can never reference anything named _
. So it's only useful for when you don't want to choose a name.
This prints what we did to stdout.
Note that this line doesn't end with |> Task.await
. That's because, although Stdout.line
returns a task, we don't need to await it because nothing happens after it.
Like storeEmail
, handleErr
is also a function.
Although type annotations are optional everywhere in Roc—because the language has 100% type inference—you could add type annotations to main
, storeEmail
, and handleErr
if you wanted to.
This will run one of the following lines depending on what value the err
argument has.
Each line does a pattern match on the shape of the error to decide whether to run, or to move on and try the next line's pattern.
Roc will do compile-time exhaustiveness checking and tell you if you forgot to handle any error cases here that could have occurred, based on the tasks that were run in storeEmail
.
This line will run if the Http.get
request from earlier encountered an HTTP error.
It handles the error by printing an error message to stderr.
The _
is where more information about the error is stored in the HttpErr
. If we wanted to print more detail about what the error was, we'd name that something other than _
and actually use it.
This line will run if the File.readUtf8
from earlier encountered a file I/O error.
It handles the error by printing an error message to stderr.
The _
is where more information about the error is stored in the FileReadErr
. If we wanted to print more detail about what the error was, we'd name that something other than _
and actually use it.
This line will run if the File.writeUtf8
from earlier encountered a file I/O error.
It handles the error by printing an error message to stderr.
The _
is where more information about the error is stored in the FileWriteErr
. If we wanted to print more detail about what the error was, we'd name that something other than _
and actually use it.