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".


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

After desugaring, this becomes:


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

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.

Note: this desugaring is very similar to that of !.

Full Code

app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br" }

import pf.Stdout

main =
    Stdout.line! (Inspect.toStr (parseNameAndYear "Alice was born in 1990"))
    Stdout.line! (Inspect.toStr (parseNameAndYearTry "Alice was born in 1990"))

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

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

expect
    parseNameAndYear "Alice was born in 1990" == Ok { name: "Alice", birthYear: 1990 }

expect
    parseNameAndYearTry "Alice was born in 1990" == Ok { name: "Alice", birthYear: 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"})