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 -> Try({ name : Str, birth_year : U16 }, [BadFormat, BadNumStr, ..]) parse_name_and_year = |str| { { before: name, after: birth_year_str } = str.split_first(" was born in ") ? |_| BadFormat birth_year = U16.from_str(birth_year_str)? Ok({ name, birth_year }) }
After desugaring, this becomes:
parse_name_and_year_try : Str -> Try({ name : Str, birth_year : U16 }, [BadFormat, BadNumStr, ..]) parse_name_and_year_try = |str| { match str.split_first(" was born in ") { Err(_) => Err(BadFormat) Ok({ before: name, after: birth_year_str }) => { match U16.from_str(birth_year_str) { Err(err2) => Err(err2) Ok(birth_year) => Ok({ name, birth_year }) } } } }
So birth_year = U16.from_str(birth_year_str)? is converted to
match U16.from_str(birth_year_str) { Err(err2) => Err(err2), Ok(birth_year) => birth_year, }
As you can see, the first version is a lot nicer!
Thanks to ?, you can write code in a familiar way and you get the benefits of Roc's
error handling to drastically reduce the likelihood of crashes.
Full Code
main! = |_| { echo!("${Str.inspect(parse_name_and_year("Alice was born in 1990"))}\n") echo!("${Str.inspect(parse_name_and_year_try("Alice was born in 1990"))}\n") Ok({}) } ### start snippet question parse_name_and_year : Str -> Try({ name : Str, birth_year : U16 }, [BadFormat, BadNumStr, ..]) parse_name_and_year = |str| { { before: name, after: birth_year_str } = str.split_first(" was born in ") ? |_| BadFormat birth_year = U16.from_str(birth_year_str)? Ok({ name, birth_year }) } ### end snippet question ### start snippet desugared parse_name_and_year_try : Str -> Try({ name : Str, birth_year : U16 }, [BadFormat, BadNumStr, ..]) parse_name_and_year_try = |str| { match str.split_first(" was born in ") { Err(_) => Err(BadFormat) Ok({ before: name, after: birth_year_str }) => { match U16.from_str(birth_year_str) { Err(err2) => Err(err2) Ok(birth_year) => Ok({ name, birth_year }) } } } } ### end snippet desugared 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({ birth_year: 1990, name: "Alice" })
Ok({ birth_year: 1990, name: "Alice" })