Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DO NOT MERGE Upgrade examples to snake_case builtins and PNC #228

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
65ac721
update flake
lukewilliamboswell Jan 9, 2025
d854efc
upgrade Arithmetic example
lukewilliamboswell Jan 9, 2025
28580c9
update BaseDict example
lukewilliamboswell Jan 9, 2025
a269966
upgrade CommandLineArgs example
lukewilliamboswell Jan 9, 2025
175dad5
upgrade CommandLineArgsFile example
lukewilliamboswell Jan 9, 2025
25d693f
upgrade CustomInspect example
lukewilliamboswell Jan 9, 2025
4c6cb23
upgrade DesugaringTry example
lukewilliamboswell Jan 9, 2025
3b35581
upgrade ElmWebApp example
lukewilliamboswell Jan 9, 2025
41ec5fe
upgrade EncodeDecode example
lukewilliamboswell Jan 9, 2025
4ef372c
upgrade ErrorHandling example
lukewilliamboswell Jan 10, 2025
21e1778
upgrade FizzBuzz example
lukewilliamboswell Jan 10, 2025
21832b9
upgrade GraphTraversal example
lukewilliamboswell Jan 10, 2025
14fd1f8
upgrade HelloWeb example
lukewilliamboswell Jan 10, 2025
b6b537a
upgrade HelloWorld example
lukewilliamboswell Jan 10, 2025
0002342
upgrade ImportFromDirectory example
lukewilliamboswell Jan 10, 2025
ea97f2b
upgrade IngestFiles example
lukewilliamboswell Jan 10, 2025
495b6d1
upgrade Json example
lukewilliamboswell Jan 10, 2025
5cad4f1
upgrade LeastSquares example
lukewilliamboswell Jan 10, 2025
b52dfd7
upgrade LoopEffect example
lukewilliamboswell Jan 10, 2025
a46415c
upgrade MultipleRocFiles example
lukewilliamboswell Jan 10, 2025
d988ca1
upgrade Parser example
lukewilliamboswell Jan 10, 2025
ffdb27d
upgrade PatternMatching example
lukewilliamboswell Jan 10, 2025
ef6ada7
upgrade RandomNumbers example
lukewilliamboswell Jan 10, 2025
0ed2054
upgrade RecordBuilder example
lukewilliamboswell Jan 10, 2025
4b5145c
upgrade Results example
lukewilliamboswell Jan 10, 2025
89600f7
upgrade SafeMath example
lukewilliamboswell Jan 10, 2025
620dc41
upgrade TowersOfHanoi example
lukewilliamboswell Jan 10, 2025
76f9cd8
upgrade Tuples example
lukewilliamboswell Jan 10, 2025
4edf0d3
update .net and go examples
Anton-4 Jan 10, 2025
0982e9c
improved arithmetic example
Anton-4 Jan 10, 2025
ce1043a
update flake
lukewilliamboswell Jan 11, 2025
011430c
examples updates, improvements
Anton-4 Jan 11, 2025
29199af
improvements and updates
Anton-4 Jan 11, 2025
c97e12b
Merge branch 'snake_case_builtins' of github.com:roc-lang/examples in…
lukewilliamboswell Jan 12, 2025
0a4fb38
new string interpolation syntax
lukewilliamboswell Jan 12, 2025
3742337
Update lambdas and Result.map
smores56 Jan 24, 2025
bff5941
update
Anton-4 Jan 24, 2025
4e7393d
use roc-random url
Anton-4 Jan 24, 2025
9496ef3
Fixed DesugaringTry
Anton-4 Jan 24, 2025
8ab67f1
fix EncodeDecode
lukewilliamboswell Jan 25, 2025
8f42d20
re-enable EncodeDecode, add final printout for all_tests.sh
lukewilliamboswell Jan 25, 2025
40de926
basic-webserver link
Anton-4 Jan 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion ci_scripts/all_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ $ROC test ./examples/CustomInspect/OpaqueTypes.roc
if [[ "$(uname)" != "Darwin" ]]; then
$ROC build --lib ./examples/GoPlatform/main.roc --output examples/GoPlatform/platform/libapp.so
go build -C examples/GoPlatform/platform -buildmode=pie -o dynhost

$ROC preprocess-host ./examples/GoPlatform/platform/dynhost ./examples/GoPlatform/platform/main.roc ./examples/GoPlatform/platform/libapp.so
$ROC build ./examples/GoPlatform/main.roc

Expand All @@ -119,3 +119,5 @@ if [[ "$(uname)" != "Darwin" ]]; then
$ROC build ./examples/DotNetPlatform/main.roc --lib --output ./examples/DotNetPlatform/platform/interop
expect ci_scripts/expect_scripts/DotNetPlatform.exp
fi

echo "All tests passed!"
2 changes: 1 addition & 1 deletion ci_scripts/expect_scripts/MultipleRocFiles.exp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ set timeout 7

spawn ./examples/MultipleRocFiles/main

expect "Hello World from interface!\r\n" {
expect "Hello World from module!\r\n" {
expect eof
exit 0
}
Expand Down
69 changes: 38 additions & 31 deletions examples/Arithmetic/main.roc
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
app [main!] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.18.0/0APbwVN1_p1mJ96tXjaoiUCr8NBGamr8G8Ac_DrXR-o.tar.br" }
app [main!] { cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.19.0/bi5zubJ-_Hva9vxxPq4kNx4WHX6oFs8OP6Ad0tCYlrY.tar.br" }

import pf.Stdout
import pf.Arg exposing [Arg]
import cli.Stdout
import cli.Arg exposing [Arg]

main! : List Arg.Arg => Result {} _
main! = \raw_args ->
main! = |raw_args|

args : { a : I32, b : I32 }
args = try read_args raw_args
args = read_args(raw_args)?

result =
[
Expand All @@ -16,44 +16,51 @@ main! = \raw_args ->
("product", args.a * args.b),
("integer quotient", args.a // args.b),
("remainder", args.a % args.b),
("exponentiation", Num.powInt args.a args.b),
("exponentiation", Num.pow_int(args.a, args.b)),
]
|> List.map \(operation, answer) ->
answer_str = Num.toStr answer
|> List.map(
|(operation, answer)| "${operation}: ${Num.to_str(answer)}",
)
|> Str.join_with("\n")

"$(operation): $(answer_str)"
|> Str.joinWith "\n"

Stdout.line! result
Stdout.line!(result)

## Reads two command-line arguments, attempts to parse them as `I32` numbers,
## and returns a task containing a record with two fields, `a` and `b`, holding
## the parsed `I32` values.
## and returns a [`Result`](https://www.roc-lang.org/builtins/Result).
##
## On success, the [`Result`](https://www.roc-lang.org/builtins/Result)
## will contain a record with two fields, `a` and `b`, holding the parsed `I32` values.
##
## If the arguments are missing, if there's an issue with parsing the arguments
## as `I32` numbers, or if the parsed numbers are outside the expected range
## (-1000 to 1000), the function will return a task that fails with an
## error `InvalidArg` or `InvalidNumStr`.
## This will fail if an argument is missing, if there's an issue with parsing
## the arguments as `I32` numbers, or if the parsed numbers are outside the
## expected range (-1000 to 1000). Then the [`Result`](https://www.roc-lang.org/builtins/Result) will contain
## an `Exit I32 Str` error.
read_args : List Arg -> Result { a : I32, b : I32 } [Exit I32 Str]
read_args = \raw_args ->
read_args = |raw_args|
arg_range_min = -1000
arg_range_max = 1000
expected_nr_of_args = 2 + 1 # +1 because first will be name or path of the program

invalid_args = Exit 1 "Error: Please provide two integers between -1000 and 1000 as arguments."
invalid_num_str = Exit 1 "Error: Invalid number format. Please provide integers between -1000 and 1000."
arg_range_min_str = Inspect.to_str(arg_range_min)
arg_range_max_str = Inspect.to_str(arg_range_max)
# TODO this function should not use Exit for modularity. Only perform this change after static dispatch has landed!
invalid_args = Exit(1, "Error: Please provide two integers between ${arg_range_min_str} and ${arg_range_max_str} as arguments.")
invalid_num_str = Exit(1, "Error: Invalid number format. Please provide integers between ${arg_range_min_str} and ${arg_range_max_str}.")

args =
if List.len raw_args != 3 then
return Err invalid_args
if List.len(raw_args) != expected_nr_of_args then
return Err(invalid_args)
else
List.map raw_args Arg.display
List.map(raw_args, Arg.display)

a_result = List.get args 1 |> Result.try Str.toI32
b_result = List.get args 2 |> Result.try Str.toI32
a_result = List.get(args, 1) |> Result.try(Str.to_i32)
b_result = List.get(args, 2) |> Result.try(Str.to_i32)

when (a_result, b_result) is
(Ok a, Ok b) ->
if a < -1000 || a > 1000 || b < -1000 || b > 1000 then
Err invalid_num_str
(Ok(a), Ok(b)) ->
if a < arg_range_min or a > arg_range_max or b < arg_range_min or b > arg_range_max then
Err(invalid_num_str)
else
Ok { a, b }
Ok({ a, b })

_ -> Err invalid_num_str
_ -> Err(invalid_num_str)
36 changes: 18 additions & 18 deletions examples/BasicDict/BasicDict.roc
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,56 @@ module []
# Below we use a Str key for the fruit name, and a U64 value for the fruit count.
fruit_dict : Dict Str U64
fruit_dict =
Dict.empty {}
|> Dict.insert "Apple" 3
|> Dict.insert "Banana" 2
Dict.empty({})
|> Dict.insert("Apple", 3)
|> Dict.insert("Banana", 2)

expect
# get the value for a key
# Dict.get returns a Result with either `Ok value` or `Err KeyNotFound`
Dict.get fruit_dict "Apple" == (Ok 3)
Dict.get(fruit_dict, "Apple") == (Ok(3))

expect
# get the length (number of key-value pairs) of a Dict
Dict.len fruit_dict == 2
Dict.len(fruit_dict) == 2

expect
# convert Dict to a Str
Inspect.toStr fruit_dict == "{\"Apple\": 3, \"Banana\": 2}"
Inspect.to_str(fruit_dict) == "{\"Apple\": 3, \"Banana\": 2}"

expect
# get all the keys
Dict.keys fruit_dict == ["Apple", "Banana"]
Dict.keys(fruit_dict) == ["Apple", "Banana"]

expect
# get all the values
Dict.values fruit_dict == [3, 2]
Dict.values(fruit_dict) == [3, 2]

expect
# convert to a list of tuples
Dict.toList fruit_dict == [("Apple", 3), ("Banana", 2)]
Dict.to_list(fruit_dict) == [("Apple", 3), ("Banana", 2)]

expect
# remove a key-value pair
Dict.remove fruit_dict "Apple"
|> Dict.remove "Banana"
|> Dict.isEmpty
Dict.remove(fruit_dict, "Apple")
|> Dict.remove("Banana")
|> Dict.is_empty

expect
# update the value of a Dict
updated_dict =
Dict.update fruit_dict "Apple" add_fruit
Dict.update(fruit_dict, "Apple", add_fruit)

# We need to account for the case when a key (=fruit) is not in the Dict.
# So we need a function like this:
add_fruit : Result U64 [Missing] -> Result U64 [Missing]
add_fruit = \value_tag ->
add_fruit = |value_tag|
when value_tag is
# If the fruit is not in the dict (=missing), we set the count to 1
Err Missing -> Ok 1
# If the fruit is in the dict (=present), we increase the count
Ok count -> Ok (count + 1)
Err(Missing) -> Ok(1)
# If the fruit is in the dict, we increase the count
Ok(count) -> Ok((count + 1))

Dict.get updated_dict "Apple" == (Ok 4)
Dict.get(updated_dict, "Apple") == (Ok(4))

# see https://www.roc-lang.org/builtins/Dict for more
10 changes: 5 additions & 5 deletions examples/BasicDict/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ A `Dict` (dictionary) lets you save a value under a key, so that you end up with
For example, you can create a Dict to keep track of how much fruit you have:

```roc
fruitDict : Dict Str U64
fruitDict =
Dict.empty {}
|> Dict.insert "Apple" 3
|> Dict.insert "Banana" 2
fruit_dict : Dict Str U64
fruit_dict =
Dict.empty({})
|> Dict.insert("Apple", 3)
|> Dict.insert("Banana", 2)
```

## Basic Dict Examples
Expand Down
21 changes: 10 additions & 11 deletions examples/CommandLineArgs/main.roc
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
# Run with `roc ./examples/CommandLineArgs/main.roc some_argument`
# !! This currently does not work in combination with --linker=legacy, see https://github.com/roc-lang/basic-cli/issues/82
app [main!] {
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.18.0/0APbwVN1_p1mJ96tXjaoiUCr8NBGamr8G8Ac_DrXR-o.tar.br",
cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.19.0/bi5zubJ-_Hva9vxxPq4kNx4WHX6oFs8OP6Ad0tCYlrY.tar.br",
}

import pf.Stdout
import pf.Arg
import cli.Stdout
import cli.Arg

main! = \raw_args ->
args = List.map raw_args Arg.display
main! = |raw_args|
args = List.map(raw_args, Arg.display)

# get the second argument, the first is the executable's path
arg_result = List.get args 1 |> Result.mapErr (\_ -> ZeroArgsGiven)
arg_result = List.get(args, 1) |> Result.map_err(ZeroArgsGiven)

when arg_result is
Err ZeroArgsGiven ->
Err (Exit 1 "Error ZeroArgsGiven:\n\tI expected one argument, but I got none.\n\tRun the app like this: `roc main.roc -- input.txt`")
Err(ZeroArgsGiven(_)) ->
Err(Exit(1, "Error ZeroArgsGiven:\n\tI expected one argument, but I got none.\n\tRun the app like this: `roc main.roc -- input.txt`"))

Ok first_argument ->
Stdout.line! "received argument: $(first_argument)"
Ok(first_argument) ->
Stdout.line!("received argument: ${first_argument}")
45 changes: 22 additions & 23 deletions examples/CommandLineArgsFile/main.roc
Original file line number Diff line number Diff line change
@@ -1,44 +1,43 @@
# Run with `roc ./examples/CommandLineArgsFile/main.roc -- examples/CommandLineArgsFile/input.txt`
# This currently does not work in combination with --linker=legacy, see https://github.com/roc-lang/basic-cli/issues/82
app [main!] {
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.18.0/0APbwVN1_p1mJ96tXjaoiUCr8NBGamr8G8Ac_DrXR-o.tar.br",
cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.19.0/bi5zubJ-_Hva9vxxPq4kNx4WHX6oFs8OP6Ad0tCYlrY.tar.br",
}

import pf.Stdout
import pf.Path exposing [Path]
import pf.Arg
import cli.Stdout
import cli.Path exposing [Path]
import cli.Arg

main! = \raw_args ->
main! = |raw_args|

# read all command line arguments
args = List.map raw_args Arg.display
args = List.map(raw_args, Arg.display)

# get the second argument, the first is the executable's path
arg_result = List.get args 1 |> Result.mapErr \_ -> ZeroArgsGiven
arg_result = List.get(args, 1) |> Result.map_err(ZeroArgsGiven)

when arg_result is
Ok arg ->
file_content_str = try read_file_to_str! (Path.from_str arg)
Ok(arg) ->
file_content_str = read_file_to_str!(Path.from_str(arg))?

Stdout.line! "file content: $(file_content_str)"
Stdout.line!("file content: ${file_content_str}")

Err ZeroArgsGiven ->
Err (Exit 1 "Error ZeroArgsGiven:\n\tI expected one argument, but I got none.\n\tRun the app like this: `roc main.roc -- path/to/input.txt`")
Err(ZeroArgsGiven(_)) ->
Err(Exit(1, "Error ZeroArgsGiven:\n\tI expected one argument, but I got none.\n\tRun the app like this: `roc main.roc -- path/to/input.txt`"))

# reads a file and puts all lines in one Str
read_file_to_str! : Path => Result Str [ReadFileErr Str]_
read_file_to_str! = \path ->
read_file_to_str! = |path|

path
|> Path.read_utf8!
|> Result.mapErr \file_read_err ->
path_str = Path.display path
|> Result.map_err(
|file_read_err|
path_str = Path.display(path)

when file_read_err is
FileReadErr _ read_err ->
read_err_str = Inspect.toStr read_err
when file_read_err is
FileReadErr(_, read_err) ->
ReadFileErr("Failed to read file:\n\t${path_str}\nWith error:\n\t${Inspect.to_str(read_err)}")

ReadFileErr "Failed to read file:\n\t$(path_str)\nWith error:\n\t$(read_err_str)"

FileReadUtf8Err _ _ ->
ReadFileErr "I could not read the file:\n\t$(path_str)\nIt contains charcaters that are not valid UTF-8:\n\t- Check if the file is encoded using a different format and convert it to UTF-8.\n\t- Check if the file is corrupted.\n\t- Find the characters that are not valid UTF-8 and fix or remove them."
FileReadUtf8Err(_, _) ->
ReadFileErr("I could not read the file:\n\t${path_str}\nIt contains charcaters that are not valid UTF-8:\n\t- Check if the file is encoded using a different format and convert it to UTF-8.\n\t- Check if the file is corrupted.\n\t- Find the characters that are not valid UTF-8 and fix or remove them."),
)
26 changes: 13 additions & 13 deletions examples/CustomInspect/OpaqueTypes.roc
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,28 @@ Color := [
Blue,
]
implements [
Inspect { toInspector: color_inspector },
Inspect { to_inspector: color_inspector },
]

color_inspector : Color -> Inspector f where f implements InspectFormatter
color_inspector = \@Color color ->
color_inspector : Color -> Inspector fmt where fmt implements InspectFormatter
color_inspector = |@Color(color)|
when color is
Red -> Inspect.str "_RED_"
Green -> Inspect.str "_GREEN_"
Blue -> Inspect.str "_BLUE_"
Red -> Inspect.str("_RED_")
Green -> Inspect.str("_GREEN_")
Blue -> Inspect.str("_BLUE_")

expect Inspect.toStr (@Color Red) == "\"_RED_\""
expect Inspect.toStr (@Color Green) == "\"_GREEN_\""
expect Inspect.toStr (@Color Blue) == "\"_BLUE_\""
expect Inspect.to_str(@Color(Red)) == "\"_RED_\""
expect Inspect.to_str(@Color(Green)) == "\"_GREEN_\""
expect Inspect.to_str(@Color(Blue)) == "\"_BLUE_\""
### end snippet color

### start snippet secret
MySecret := Str implements [
Inspect { toInspector: my_secret_inspector },
Inspect { to_inspector: my_secret_inspector },
]

my_secret_inspector : MySecret -> Inspector f where f implements InspectFormatter
my_secret_inspector = \@MySecret _ -> Inspect.str "******* REDACTED *******"
my_secret_inspector : MySecret -> Inspector fmt where fmt implements InspectFormatter
my_secret_inspector = |@MySecret(_)| Inspect.str("******* REDACTED *******")

expect Inspect.toStr (@MySecret "password1234") == "\"******* REDACTED *******\""
expect Inspect.to_str(@MySecret("password1234")) == "\"******* REDACTED *******\""
### end snippet secret
22 changes: 12 additions & 10 deletions examples/DesugaringTry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
convenient way without adding new functionality to the language itself.
</details>

Desugaring converts syntax sugar (like `x + 1`) into more fundamental operations (like `Num.add x 1`).
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"`.
Expand All @@ -18,18 +18,20 @@ file:main.roc:snippet:question

After desugaring, this becomes:
```roc
file:main.roc:snippet:try
file:main.roc:snippet:desugared
```

[Result.try](https://www.roc-lang.org/builtins/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`.
So `birth_year = Str.to_u16(birth_year_str)?` is converted to

`birthYear = Str.toU16? birthYearStr` is converted to `Str.toU16 birthYearStr |> Result.try \birthYear ->`.
```roc
when Str.to_u16(birth_year_str) is
Err(err2) -> return 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 mostly familiar way while also getting the benefits of Roc's
error handling.
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
```roc
Expand All @@ -42,6 +44,6 @@ Run this from the directory that has `main.roc` in it:

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