Desugaring ?

What's syntax sugar?

Syntax within a programming language that is designed to make things easier to read or express. It allows developers to write code in a more concise, readable, or convenient way without adding new functionality to the language itself.

Desugaring converts syntax sugar (like x + 1) into more fundamental operations (like Num.add x 1).

Let's see how ? is desugared. In this example we will extract the name and birth year from a string like "Alice was born in 1990".


parse_name_and_year : Str -> Result { name : Str, birth_year : U16 } _
parse_name_and_year = \str ->
    { before: name, after: birth_year_str } = Str.splitFirst? str " was born in "
    birth_year = Str.toU16? birth_year_str
    Ok { name, birth_year }

After desugaring, this becomes:


    str
    |> Str.splitFirst " was born in "
    |> Result.try \{ before: name, after: birth_year_str } ->
        Str.toU16 birth_year_str
        |> Result.try \birth_year ->
            Ok { name, birth_year }

Result.try takes the success value from a given Result and uses that to generate a new Result. It's type is Result a err, (a -> Result b err) -> Result b err.

birthYear = Str.toU16? birthYearStr is converted to Str.toU16 birthYearStr |> Result.try \birthYear ->. As you can see, the first version is a lot nicer!

Thanks to ?, you can write code in a mostly familiar way while also getting the benefits of Roc's error handling.

Full Code

app [main!] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.18.0/0APbwVN1_p1mJ96tXjaoiUCr8NBGamr8G8Ac_DrXR-o.tar.br" }

import pf.Stdout

main! = \_args ->
    try Stdout.line! (Inspect.toStr (parse_name_and_year "Alice was born in 1990"))
    try Stdout.line! (Inspect.toStr (parse_name_and_year_try "Alice was born in 1990"))

    Ok {}

### start snippet question
parse_name_and_year : Str -> Result { name : Str, birth_year : U16 } _
parse_name_and_year = \str ->
    { before: name, after: birth_year_str } = Str.splitFirst? str " was born in "
    birth_year = Str.toU16? birth_year_str
    Ok { name, birth_year }
### end snippet question

parse_name_and_year_try = \str ->
    ### start snippet try
    str
    |> Str.splitFirst " was born in "
    |> Result.try \{ before: name, after: birth_year_str } ->
        Str.toU16 birth_year_str
        |> Result.try \birth_year ->
            Ok { name, birth_year }
### end snippet try

expect
    parse_name_and_year "Alice was born in 1990" == Ok { name: "Alice", birth_year: 1990 }

expect
    parse_name_and_year_try "Alice was born in 1990" == Ok { name: "Alice", birth_year: 1990 }

Output

Run this from the directory that has main.roc in it:

$ roc main.roc
(Ok {birthYear: 1990, name: "Alice"})
(Ok {birthYear: 1990, name: "Alice"})