mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
Update to basic-cli 0.8.1
This commit is contained in:
parent
7f2e2d0803
commit
09574203ce
18 changed files with 156 additions and 146 deletions
|
@ -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)"
|
||||||
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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",
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)"
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 [
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue