Update to basic-cli 0.8.1

This commit is contained in:
Richard Feldman 2024-01-26 12:05:28 -05:00
parent 7f2e2d0803
commit 09574203ce
No known key found for this signature in database
GPG key ID: F1F21AA5B1D9E43B
18 changed files with 156 additions and 146 deletions

View file

@ -872,10 +872,10 @@ mod cli_run {
&[], &[],
indoc!( indoc!(
r#" r#"
This roc file can print it's own source code. The source is: This roc file can print its own source code. The source is:
app "ingested-file" app "ingested-file"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [ imports [
pf.Stdout, pf.Stdout,
"ingested-file.roc" as ownCode : Str, "ingested-file.roc" as ownCode : Str,
@ -883,7 +883,7 @@ mod cli_run {
provides [main] to pf provides [main] to pf
main = main =
Stdout.line "\nThis roc file can print it's own source code. The source is:\n\n\(ownCode)" Stdout.line "\nThis roc file can print its own source code. The source is:\n\n$(ownCode)"
"# "#
), ),

View file

@ -1,7 +1,7 @@
app "hello" app "hello"
packages { packages {
pf: pf:
"https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br", "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br",
} }
imports [pf.Stdout] imports [pf.Stdout]
provides [main] to pf provides [main] to pf

View file

@ -24,7 +24,7 @@ Full {
Newline, Newline,
], ],
package_name: @31-145 PackageName( package_name: @31-145 PackageName(
"https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br", "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br",
), ),
}, },
[ [

View file

@ -1,6 +1,6 @@
app "hello" app "hello"
packages { pf: packages { pf:
"https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br"
} }
imports [pf.Stdout] imports [pf.Stdout]
provides [main] to pf provides [main] to pf

View file

@ -1,5 +1,5 @@
app "args" app "args"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Stdout, pf.Arg, pf.Task.{ Task }] imports [pf.Stdout, pf.Arg, pf.Task.{ Task }]
provides [main] to pf provides [main] to pf

View file

@ -1,5 +1,5 @@
app "countdown" app "countdown"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Stdin, pf.Stdout, pf.Task.{ await, loop }] imports [pf.Stdin, pf.Stdout, pf.Task.{ await, loop }]
provides [main] to pf provides [main] to pf

View file

@ -1,5 +1,5 @@
app "echo" app "echo"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Stdin, pf.Stdout, pf.Task.{ Task }] imports [pf.Stdin, pf.Stdout, pf.Task.{ Task }]
provides [main] to pf provides [main] to pf

View file

@ -1,5 +1,5 @@
app "env" app "env"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Stdout, pf.Stderr, pf.Env, pf.Task.{ Task }] imports [pf.Stdout, pf.Stderr, pf.Env, pf.Task.{ Task }]
provides [main] to pf provides [main] to pf

View file

@ -1,5 +1,5 @@
app "file-io" app "file-io"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [ imports [
pf.Stdout, pf.Stdout,
pf.Stderr, pf.Stderr,

View file

@ -1,5 +1,5 @@
app "form" app "form"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Stdin, pf.Stdout, pf.Task.{ await, Task }] imports [pf.Stdin, pf.Stdout, pf.Task.{ await, Task }]
provides [main] to pf provides [main] to pf

View file

@ -1,5 +1,5 @@
app "http-get" app "http-get"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Http, pf.Task.{ Task }, pf.Stdin, pf.Stdout] imports [pf.Http, pf.Task.{ Task }, pf.Stdin, pf.Stdout]
provides [main] to pf provides [main] to pf

View file

@ -1,5 +1,5 @@
app "ingested-file-bytes" app "ingested-file-bytes"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [ imports [
pf.Stdout, pf.Stdout,
"../../LICENSE" as license : _, # A type hole can also be used here. "../../LICENSE" as license : _, # A type hole can also be used here.

View file

@ -1,5 +1,5 @@
app "ingested-file" app "ingested-file"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [ imports [
pf.Stdout, pf.Stdout,
"ingested-file.roc" as ownCode : Str, "ingested-file.roc" as ownCode : Str,
@ -7,4 +7,4 @@ app "ingested-file"
provides [main] to pf provides [main] to pf
main = main =
Stdout.line "\nThis roc file can print it's own source code. The source is:\n\n\(ownCode)" Stdout.line "\nThis roc file can print its own source code. The source is:\n\n$(ownCode)"

View file

@ -1,5 +1,5 @@
app "helloWorld" app "helloWorld"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Stdout] imports [pf.Stdout]
provides [main] to pf provides [main] to pf

View file

@ -2,7 +2,7 @@
# Shows how Roc values can be logged # Shows how Roc values can be logged
# #
app "inspect-logging" app "inspect-logging"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [ imports [
pf.Stdout, pf.Stdout,
Community, Community,

View file

@ -1,6 +1,6 @@
app "example" app "example"
packages { packages {
cli: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br", cli: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br",
parser: "https://github.com/lukewilliamboswell/roc-parser/releases/download/0.5/KB-TITJ4DfunB88sFBWjCtCGV7LRRDdTH5JUXp4gIb8.tar.br", parser: "https://github.com/lukewilliamboswell/roc-parser/releases/download/0.5/KB-TITJ4DfunB88sFBWjCtCGV7LRRDdTH5JUXp4gIb8.tar.br",
} }
imports [ imports [

View file

@ -1,6 +1,6 @@
# Platforms # Platforms
Something that sets Roc apart from other programming languages is its <span class="nowrap">*platforms and applications*</span> architecture. Something that sets Roc apart from other programming languages is its <span class="nowrap">_platforms and applications_</span> architecture.
## [Applications](#applications) {#applications} ## [Applications](#applications) {#applications}
@ -8,7 +8,7 @@ Here is a Roc application that prints `"Hello, World!"` to the command line:
```roc ```roc
app "hello" app "hello"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Stdout] imports [pf.Stdout]
provides [main] to pf provides [main] to pf
@ -26,19 +26,20 @@ Also like many game engines and Web frameworks, Roc platforms have a high-level
Here are some example Roc platforms, and functionality they might provide: Here are some example Roc platforms, and functionality they might provide:
* A Roc game engine platform might provide functionality for rendering and sound. - A Roc game engine platform might provide functionality for rendering and sound.
* A Roc Web server platform (like [basic-webserver](https://github.com/roc-lang/basic-webserver)) probably would not provide functionality for rendering and sound, but it might provide functionality for responding to incoming HTTP requests—which a game engine platform likely would not. - A Roc Web server platform (like [basic-webserver](https://github.com/roc-lang/basic-webserver)) probably would not provide functionality for rendering and sound, but it might provide functionality for responding to incoming HTTP requests—which a game engine platform likely would not.
* A Roc native [GUI](https://en.wikipedia.org/wiki/Graphical_user_interface) platform might provide functionality for defining native operating system UI elements, whereas a game engine platform might focus more on rendering with [shaders](https://en.wikipedia.org/wiki/Shader), and a Web server platform would not have GUI functionality at all. - A Roc native [GUI](https://en.wikipedia.org/wiki/Graphical_user_interface) platform might provide functionality for defining native operating system UI elements, whereas a game engine platform might focus more on rendering with [shaders](https://en.wikipedia.org/wiki/Shader), and a Web server platform would not have GUI functionality at all.
These are broad domains, but platforms can be much more specific than this. For example, anyone could make a platform for writing [Vim](https://en.wikipedia.org/wiki/Vim_(text_editor)) plugins, or [Postgres](https://en.wikipedia.org/wiki/PostgreSQL) extensions, or robots ([which has already happened](https://roc.zulipchat.com/#narrow/stream/304902-show-and-tell/topic/Roc.20on.20a.20microcontroller/near/286678630)), or even [implementing servo logic for a clock that physically turns panels to simulate an LCD](https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/Roc.20Clock/near/327939600). You really can get as specific as you like! These are broad domains, but platforms can be much more specific than this. For example, anyone could make a platform for writing [Vim](<https://en.wikipedia.org/wiki/Vim_(text_editor)>) plugins, or [Postgres](https://en.wikipedia.org/wiki/PostgreSQL) extensions, or robots ([which has already happened](https://roc.zulipchat.com/#narrow/stream/304902-show-and-tell/topic/Roc.20on.20a.20microcontroller/near/286678630)), or even [implementing servo logic for a clock that physically turns panels to simulate an LCD](https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/Roc.20Clock/near/327939600). You really can get as specific as you like!
Platforms can also be designed to have a single, specific application run on them. For example, you can make a platform that is essentially "your entire existing code base in another language," and then use Roc as an embedded language within that code base. For example, [Vendr](https://www.vendr.com/careers) is using this strategy to call Roc functions from their [Node.js](https://nodejs.org/en) backend using [roc-esbuild](https://github.com/vendrinc/roc-esbuild), as a way to incrementally transition code from Node to Roc. Platforms can also be designed to have a single, specific application run on them. For example, you can make a platform that is essentially "your entire existing code base in another language," and then use Roc as an embedded language within that code base. For example, [Vendr](https://www.vendr.com/careers) is using this strategy to call Roc functions from their [Node.js](https://nodejs.org/en) backend using [roc-esbuild](https://github.com/vendrinc/roc-esbuild), as a way to incrementally transition code from Node to Roc.
## [Platform scope](#scope) {#scope} ## [Platform scope](#scope) {#scope}
Roc platforms have a broader scope of responsibility than game engines or Web frameworks. In addition to providing a nice domain-specific interface, platforms are also responsible for: Roc platforms have a broader scope of responsibility than game engines or Web frameworks. In addition to providing a nice domain-specific interface, platforms are also responsible for:
* Tailoring memory management to that domain (more on this later)
* Providing all I/O primitives - Tailoring memory management to that domain (more on this later)
- Providing all I/O primitives
In most languages, I/O primitives come with the standard library. In Roc, the [standard library](https://www.roc-lang.org/builtins/) contains only data structures; an application gets all of its I/O primitives from its platform. For example, in the "Hello, World" application above, the `Stdout.line` function comes from the `basic-cli` platform itself, not from Roc's standard library. In most languages, I/O primitives come with the standard library. In Roc, the [standard library](https://www.roc-lang.org/builtins/) contains only data structures; an application gets all of its I/O primitives from its platform. For example, in the "Hello, World" application above, the `Stdout.line` function comes from the `basic-cli` platform itself, not from Roc's standard library.
@ -48,7 +49,7 @@ This design has a few benefits.
Some I/O operations make sense in some use cases but not others. Some I/O operations make sense in some use cases but not others.
For example, suppose I'm building an application on a platform for command-line interfaces, and I use a third-party package which sometimes blocks the program while it waits for [standard input](https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin)). This might be fine for my command-line application, but it would probably be a very bad fit if I'm using a webserver. Similarly, a package which does some occasional file I/O for caching might work fine on either of those platforms, but might break in surprising ways when used in a platform that's designed to run in a browser on WebAssembly—since browsers don't offer arbitrary file I/O access! For example, suppose I'm building an application on a platform for command-line interfaces, and I use a third-party package which sometimes blocks the program while it waits for [standard input](<https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin)>). This might be fine for my command-line application, but it would probably be a very bad fit if I'm using a webserver. Similarly, a package which does some occasional file I/O for caching might work fine on either of those platforms, but might break in surprising ways when used in a platform that's designed to run in a browser on WebAssembly—since browsers don't offer arbitrary file I/O access!
Because Roc's I/O primitives come from platforms, these mismatches can be prevented at build time. The browser-based platform would not expose file I/O primitives, the webserver wouldn't expose a way to block on reading from standard input, and so on. (Note that there's a design in the works for allowing packages which perform I/O to work across multiple platforms—but only platforms which support the I/O primitives it requires—but this design has not yet been implemented.) Because Roc's I/O primitives come from platforms, these mismatches can be prevented at build time. The browser-based platform would not expose file I/O primitives, the webserver wouldn't expose a way to block on reading from standard input, and so on. (Note that there's a design in the works for allowing packages which perform I/O to work across multiple platforms—but only platforms which support the I/O primitives it requires—but this design has not yet been implemented.)
@ -58,7 +59,7 @@ Since platforms have exclusive control over all I/O primitives, one of the thing
[This talk](https://www.youtube.com/watch?v=cpQwtwVKAfU&t=75s) shows an example of taking this idea a step further with a "safe scripting" platform for writing command-line scripts. The idea is that you could download a script from the Internet and run it on this platform without worrying that the script would do bad things to your computer, because the platform would (much like a Web browser) show you specific prompts before allowing the script to do potentially harmful I/O, such as filesystem operations. [This talk](https://www.youtube.com/watch?v=cpQwtwVKAfU&t=75s) shows an example of taking this idea a step further with a "safe scripting" platform for writing command-line scripts. The idea is that you could download a script from the Internet and run it on this platform without worrying that the script would do bad things to your computer, because the platform would (much like a Web browser) show you specific prompts before allowing the script to do potentially harmful I/O, such as filesystem operations.
These security guarantees can be relied on because platforms have *exclusive* control over all I/O primitives, including how they are implemented. There are no escape hatches that a malicious program could use to get around these, either; for example, Roc programs that want to call functions in other languages must do so using primitives provided by the platform, which the platform can disallow (or sandbox with end-user prompts) in the same way. These security guarantees can be relied on because platforms have _exclusive_ control over all I/O primitives, including how they are implemented. There are no escape hatches that a malicious program could use to get around these, either; for example, Roc programs that want to call functions in other languages must do so using primitives provided by the platform, which the platform can disallow (or sandbox with end-user prompts) in the same way.
### [Performance benefits](#performance) {#performance} ### [Performance benefits](#performance) {#performance}
@ -75,8 +76,9 @@ To understand how platforms can tailor automatic memory management to their part
### [The Host and the Roc API](#host-and-roc-api) {#host-and-roc-api} ### [The Host and the Roc API](#host-and-roc-api) {#host-and-roc-api}
Each platform consists of two parts: Each platform consists of two parts:
* **The Roc API** is the part that application authors see. For example, `Stdout.line` is part of basic-cli's Roc API.
* **The Host** is the under-the-hood implementation written in a language other than Roc. For example, basic-cli's host is written in Rust. It has a Rust function which implements the behavior of the `Stdout.line` operation, and all the other I/O operations it supports. - **The Roc API** is the part that application authors see. For example, `Stdout.line` is part of basic-cli's Roc API.
- **The Host** is the under-the-hood implementation written in a language other than Roc. For example, basic-cli's host is written in Rust. It has a Rust function which implements the behavior of the `Stdout.line` operation, and all the other I/O operations it supports.
This design means that application authors don't necessarily need to know (or care) about the non-Roc language being used to implement the platform's host. That can be a behind-the-scenes implementation detail that only the platform's author(s) are concerned with. Application authors only interact with the public-facing Roc API. This design means that application authors don't necessarily need to know (or care) about the non-Roc language being used to implement the platform's host. That can be a behind-the-scenes implementation detail that only the platform's author(s) are concerned with. Application authors only interact with the public-facing Roc API.
@ -97,6 +99,7 @@ When a compiled Roc program runs, it's actually the host—not the Roc applicati
Knowing this, a useful mental model for how Roc platforms and applications interact at the implementation level is: the Roc application compiles down to a C library which the platform can choose to call (or not). Knowing this, a useful mental model for how Roc platforms and applications interact at the implementation level is: the Roc application compiles down to a C library which the platform can choose to call (or not).
This is essentially what's happening behind the scenes when you run `roc build`. Specifically: This is essentially what's happening behind the scenes when you run `roc build`. Specifically:
1. The Roc compiler builds the Roc application into a binary [object file](https://en.wikipedia.org/wiki/Object_file) 1. The Roc compiler builds the Roc application into a binary [object file](https://en.wikipedia.org/wiki/Object_file)
2. Since that application specified its platform, the compiler then looks up the platform's host implementation (which the platform will have provided as an already-compiled binary) 2. Since that application specified its platform, the compiler then looks up the platform's host implementation (which the platform will have provided as an already-compiled binary)
3. Now that it has a binary for the Roc application and a binary for the host, it links them together into one combined binary in which the host portion calls the application portion as many times as it likes. 3. Now that it has a binary for the Roc application and a binary for the host, it links them together into one combined binary in which the host portion calls the application portion as many times as it likes.
@ -109,6 +112,6 @@ Every Roc application has exactly one platform. That platform provides all the I
This I/O design has [security benefits](#security), [ecosystem benefits](#ecosystem), and [performance benefits](#performance). The [domain-specific memory management](#memory) platforms can implement can offer additional benefits as well. This I/O design has [security benefits](#security), [ecosystem benefits](#ecosystem), and [performance benefits](#performance). The [domain-specific memory management](#memory) platforms can implement can offer additional benefits as well.
Applications only interact with the *Roc API* portion of a platform, but there is also a *host* portion (written in a different language) that works behind the scenes. The host determines how the program starts, how memory is allocated and deallocated, and how I/O primitives are implemented. Applications only interact with the _Roc API_ portion of a platform, but there is also a _host_ portion (written in a different language) that works behind the scenes. The host determines how the program starts, how memory is allocated and deallocated, and how I/O primitives are implemented.
Anyone can implement their own platform. There isn't yet an official guide about how to do this, so the best way to get help if you'd like to create a platform is to [say hi in the `#beginners` channel](https://roc.zulipchat.com/#narrow/stream/231634-beginners) on [Roc Zulip!](https://roc.zulipchat.com) Anyone can implement their own platform. There isn't yet an official guide about how to do this, so the best way to get help if you'd like to create a platform is to [say hi in the `#beginners` channel](https://roc.zulipchat.com/#narrow/stream/231634-beginners) on [Roc Zulip!](https://roc.zulipchat.com)

View file

@ -164,7 +164,7 @@ Make a file named `main.roc` and put this in it:
```roc ```roc
app "hello" app "hello"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Stdout] imports [pf.Stdout]
provides [main] to pf provides [main] to pf
@ -367,7 +367,7 @@ addAndStringify = \counts ->
Num.toStr (counts.birds + counts.iguanas) Num.toStr (counts.birds + counts.iguanas)
``` ```
The function now takes a _record_, which is a group of named values. Records are not [objects](https://en.wikipedia.org/wiki/Object_(computer_science)); they don't have methods or inheritance, they just store information. The function now takes a _record_, which is a group of named values. Records are not [objects](<https://en.wikipedia.org/wiki/Object_(computer_science)>); they don't have methods or inheritance, they just store information.
The expression `{ birds: 5, iguanas: 7 }` defines a record with two _fields_ (the `birds` field and the `iguanas` field) and then assigns the number `5` to the `birds` field and the number `7` to the `iguanas` field. Order doesn't matter with record fields; we could have also specified `iguanas` first and `birds` second, and Roc would consider it the exact same record. The expression `{ birds: 5, iguanas: 7 }` defines a record with two _fields_ (the `birds` field and the `iguanas` field) and then assigns the number `5` to the `birds` field and the number `7` to the `iguanas` field. Order doesn't matter with record fields; we could have also specified `iguanas` first and `birds` second, and Roc would consider it the exact same record.
@ -474,7 +474,7 @@ table = \{
-> ->
``` ```
This is using *optional field destructuring* to destructure a record while This is using _optional field destructuring_ to destructure a record while
also providing default values for any fields that might be missing. also providing default values for any fields that might be missing.
Here's the type of `table`: Here's the type of `table`:
@ -490,8 +490,8 @@ table :
-> Table -> Table
``` ```
This says that `table` takes a record with two *required* fields, `height` and This says that `table` takes a record with two _required_ fields, `height` and
`width`, and two *optional* fields, `title` and `description`. It also says that `width`, and two _optional_ fields, `title` and `description`. It also says that
the `height` and `width` fields have the type `Pixels`, a type alias for some the `height` and `width` fields have the type `Pixels`, a type alias for some
numeric type, and the `title` and `description` fields have the type `Str`. numeric type, and the `title` and `description` fields have the type `Str`.
This means you can choose to omit the `title`, `description`, or both fields, when calling the function... but if you provide them, they must have the type `Str`. This means you can choose to omit the `title`, `description`, or both fields, when calling the function... but if you provide them, they must have the type `Str`.
@ -504,7 +504,7 @@ These default values can reference other expressions in the record destructure;
Destructuring is the only way to implement a record with optional fields. For example, if you write the expression `config.title` and `title` is an Destructuring is the only way to implement a record with optional fields. For example, if you write the expression `config.title` and `title` is an
optional field, you'll get a compile error. optional field, you'll get a compile error.
This means it's never possible to end up with an *optional value* that exists This means it's never possible to end up with an _optional value_ that exists
outside a record field. Optionality is a concept that exists only in record outside a record field. Optionality is a concept that exists only in record
fields, and it's intended for the use case of config records like this. The fields, and it's intended for the use case of config records like this. The
ergonomics of destructuring mean this wouldn't be a good fit for data modeling, consider using a `Result` type instead. ergonomics of destructuring mean this wouldn't be a good fit for data modeling, consider using a `Result` type instead.
@ -861,6 +861,7 @@ These functions demonstrate a common pattern in Roc: operations that can fail re
Result.withDefault (List.get ["a", "b", "c"] 100) "" Result.withDefault (List.get ["a", "b", "c"] 100) ""
# returns "" because that's the default we said to use if List.get returned an Err # returns "" because that's the default we said to use if List.get returned an Err
``` ```
```roc ```roc
Result.isOk (List.get ["a", "b", "c"] 1) Result.isOk (List.get ["a", "b", "c"] 1)
# returns `Bool.true` because `List.get` returned an `Ok` tag. (The payload gets ignored.) # returns `Bool.true` because `List.get` returned an `Ok` tag. (The payload gets ignored.)
@ -875,9 +876,9 @@ that quite does what you want, and you might find yourself calling `List.get` re
retrieve every element in the list and use it to build up the new value you want. That approach retrieve every element in the list and use it to build up the new value you want. That approach
can work, but it has a few downsides: can work, but it has a few downsides:
* Each `List.get` call returns a `Result` that must be dealt with, even though you plan to use every element in the list anyway - Each `List.get` call returns a `Result` that must be dealt with, even though you plan to use every element in the list anyway
* There's a runtime performance overhead associated with each of these `Result`s, which you won't find in other "look at every element in the list" operations like `List.keepIf`. - There's a runtime performance overhead associated with each of these `Result`s, which you won't find in other "look at every element in the list" operations like `List.keepIf`.
* It's more verbose than the alternative we're about to discuss - It's more verbose than the alternative we're about to discuss
The `List.walk` function gives you a way to walk over the elements in a list and build up whatever The `List.walk` function gives you a way to walk over the elements in a list and build up whatever
return value you like. It's a great alternative to calling `List.get` on every element in the list return value you like. It's a great alternative to calling `List.get` on every element in the list
@ -932,6 +933,7 @@ When you have nested function calls, sometimes it can be clearer to write them i
```roc ```roc
Result.withDefault (List.get ["a", "b", "c"] 1) "" Result.withDefault (List.get ["a", "b", "c"] 1) ""
``` ```
```roc ```roc
List.get ["a", "b", "c"] 1 List.get ["a", "b", "c"] 1
|> Result.withDefault "" |> Result.withDefault ""
@ -954,6 +956,7 @@ One reason the `|>` operator injects the value as the first argument is to make
```roc ```roc
List.append ["a", "b", "c"] "d" List.append ["a", "b", "c"] "d"
``` ```
```roc ```roc
["a", "b", "c"] ["a", "b", "c"]
|> List.append "d" |> List.append "d"
@ -964,9 +967,11 @@ Another example is `Num.div`. All three of the following do the same thing, beca
```roc ```roc
first / second first / second
``` ```
```roc ```roc
Num.div first second Num.div first second
``` ```
```roc ```roc
first |> Num.div second first |> Num.div second
``` ```
@ -1154,6 +1159,7 @@ Here, Roc's compiler will infer that `color`'s type is `[Red, Yellow, Green]`, b
### [Opaque Types](#opaque-types) {#opaque-types} ### [Opaque Types](#opaque-types) {#opaque-types}
A type can be defined to be opaque to hide its internal structure. This is a lot more amazing than it may seem. It can make your code more modular, robust, and easier to read: A type can be defined to be opaque to hide its internal structure. This is a lot more amazing than it may seem. It can make your code more modular, robust, and easier to read:
- If a type is opaque you can modify its internal structure and be certain that no dependencies need to be updated. - If a type is opaque you can modify its internal structure and be certain that no dependencies need to be updated.
- You can prevent that data needs to be checked multiple times. For example, you can create an opaque `NonEmptyList` from a `List` after you've checked it. Now all functions that you pass this `NonEmptyList` to do not need to handle the empty list case. - You can prevent that data needs to be checked multiple times. For example, you can create an opaque `NonEmptyList` from a `List` after you've checked it. Now all functions that you pass this `NonEmptyList` to do not need to handle the empty list case.
- Having the type `Username` in a type signature gives you more context compared to `Str`. Even if the `Username` is an opaque type for `Str`. - Having the type `Username` in a type signature gives you more context compared to `Str`. Even if the `Username` is an opaque type for `Str`.
@ -1205,7 +1211,7 @@ Choosing a size depends on your performance needs and the range of numbers you w
Here are the different fixed-size integer types that Roc supports: Here are the different fixed-size integer types that Roc supports:
| Range | Type | | Range | Type |
|-------------------------------------------------------------------------------------------------------------------|--------| | ----------------------------------------------------------------------------------------------------------------- | ------ |
| `-128` <br> `127` | `I8` | | `-128` <br> `127` | `I8` |
| `0` <br> `255` | `U8` | | `0` <br> `255` | `U8` |
| `-32_768` <br> `32_767` | `I16` | | `-32_768` <br> `32_767` | `I16` |
@ -1260,9 +1266,11 @@ There's also an `Int` type which is only compatible with integers, and a `Frac`
```roc ```roc
Num.xor : Int a, Int a -> Int a Num.xor : Int a, Int a -> Int a
``` ```
```roc ```roc
Num.cos : Frac a -> Frac a Num.cos : Frac a -> Frac a
``` ```
When you write a number literal in Roc, it has the type `Num *`. So you could call `Num.xor 1 1` and also `Num.cos 1` and have them all work as expected; the number literal `1` has the type `Num *`, which is compatible with the more constrained types `Int` and `Frac`. For the same reason, you can pass number literals to functions expecting even more constrained types, like `I32` or `F64`. When you write a number literal in Roc, it has the type `Num *`. So you could call `Num.xor 1 1` and also `Num.cos 1` and have them all work as expected; the number literal `1` has the type `Num *`, which is compatible with the more constrained types `Int` and `Frac`. For the same reason, you can pass number literals to functions expecting even more constrained types, like `I32` or `F64`.
### [Number Literals](#number-literals) {#number-literals} ### [Number Literals](#number-literals) {#number-literals}
@ -1383,7 +1391,7 @@ Each `.roc` file is a separate module and contains Roc code for different purpos
- **Interfaces** provide functions which can be imported into other modules. - **Interfaces** provide functions which can be imported into other modules.
- **Packages** organise modules to share functionality across applications and platforms. - **Packages** organise modules to share functionality across applications and platforms.
- **Platforms** provide effects such as IO to interface with the outside world. - **Platforms** provide effects such as IO to interface with the outside world.
- **Hosted** *note this module type is likely to be deprecated soon*. - **Hosted** _note this module type is likely to be deprecated soon_.
### [Builtin Modules](#builtin-modules) {#builtin-modules} ### [Builtin Modules](#builtin-modules) {#builtin-modules}
@ -1412,7 +1420,7 @@ Let's take a closer look at the part of `main.roc` above the `main` def:
```roc ```roc
app "hello" app "hello"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Stdout] imports [pf.Stdout]
provides [main] to pf provides [main] to pf
``` ```
@ -1424,7 +1432,7 @@ The line `app "hello"` shows that this module is a Roc application. The "hello"
The remaining lines all involve the [platform](https://github.com/roc-lang/roc/wiki/Roc-concepts-explained#platform) this application is built on: The remaining lines all involve the [platform](https://github.com/roc-lang/roc/wiki/Roc-concepts-explained#platform) this application is built on:
```roc ```roc
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Stdout] imports [pf.Stdout]
provides [main] to pf provides [main] to pf
``` ```
@ -1523,7 +1531,7 @@ Let's start with a basic "Hello World" program.
```roc ```roc
app "cli-tutorial" app "cli-tutorial"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Stdout] imports [pf.Stdout]
provides [main] to pf provides [main] to pf
@ -1557,7 +1565,7 @@ Let's change `main` to read a line from `stdin`, and then print what we got:
```roc ```roc
app "cli-tutorial" app "cli-tutorial"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Stdout, pf.Stdin, pf.Task] imports [pf.Stdout, pf.Stdin, pf.Task]
provides [main] to pf provides [main] to pf
@ -1602,7 +1610,7 @@ This works, but we can make it a little nicer to read. Let's change it to the fo
```roc ```roc
app "cli-tutorial" app "cli-tutorial"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br" }
imports [pf.Stdout, pf.Stdin, pf.Task.{ await }] imports [pf.Stdout, pf.Stdin, pf.Task.{ await }]
provides [main] to pf provides [main] to pf
@ -2062,7 +2070,7 @@ These are all the reserved keywords in Roc. You can't choose any of these as nam
Here are various Roc expressions involving operators, and what they desugar to. Here are various Roc expressions involving operators, and what they desugar to.
| Expression | Desugars To | | Expression | Desugars To |
| ----------------------------- | ------------------ | | ---------------------------- | ------------------ |
| `a + b` | `Num.add a b` | | `a + b` | `Num.add a b` |
| `a - b` | `Num.sub a b` | | `a - b` | `Num.sub a b` |
| `a * b` | `Num.mul a b` | | `a * b` | `Num.mul a b` |
@ -2079,6 +2087,5 @@ Here are various Roc expressions involving operators, and what they desugar to.
| <code>a \|> f</code> | `f a` | | <code>a \|> f</code> | `f a` |
| <code>f a b \|> g x y</code> | `g (f a b) x y` | | <code>f a b \|> g x y</code> | `g (f a b) x y` |
</section> </section>
<script type="text/javascript" src="/builtins/search.js" defer></script> <script type="text/javascript" src="/builtins/search.js" defer></script>