mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-11 05:34:11 +03:00
Merge remote-tracking branch 'origin/main' into https-packages
This commit is contained in:
commit
08764787f5
@ -3,7 +3,7 @@
|
||||
Roc is not ready for a 0.1 release yet, but we do have:
|
||||
|
||||
- [**installation** guide](https://github.com/roc-lang/roc/tree/main/getting_started)
|
||||
- [**tutorial**](https://github.com/roc-lang/roc/blob/main/TUTORIAL.md)
|
||||
- [**tutorial**](https://roc-lang.org/tutorial)
|
||||
- [**docs** for the standard library](https://www.roc-lang.org/builtins/Str)
|
||||
- [frequently asked questions](https://github.com/roc-lang/roc/blob/main/FAQ.md)
|
||||
- [Zulip chat](https://roc.zulipchat.com) for help, questions and discussions
|
||||
|
2142
TUTORIAL.md
2142
TUTORIAL.md
File diff suppressed because it is too large
Load Diff
@ -208,3 +208,18 @@ The diagram below illustrates this process.
|
||||
|
||||
|
||||
![Diagram showing how host-to-app calls are linked.](./docs/host-to-app-calls.svg)
|
||||
|
||||
## Tips for debugging Wasm code generation
|
||||
|
||||
In general, WebAssembly runtimes often have terrible error messages. Especially command-line ones. And most especially Wasm3, which we use nonetheless because it's fast.
|
||||
|
||||
- Install the WABT (WebAssembly Binary Toolkit)
|
||||
- We have a debug setting to dump out the test binary. In `gen_wasm/src/lib.rs`, set `DEBUG_LOG_SETTINGS.keep_test_binary` to `true`
|
||||
- Run `wasm-validate` to make sure the module is valid WebAssembly
|
||||
- Use `wasm-objdump` with options `-d`, `-x`, or `-s` depending on the issue
|
||||
- Browsers are **much** better for debugging Wasm than any of the command line tools.
|
||||
- I highly recommend this, even if you are more comfortable with the command line than the browser!
|
||||
- Browsers have by far the best error messages and debugging tools. There is nothing comparable on the command line.
|
||||
- We have a web page that can run gen_wasm unit tests:
|
||||
crates/compiler/test_gen/src/helpers/debug-wasm-test.html
|
||||
- The page itself contains instructions explaining how to open the browser debug tools. No web dev background should be required. If there's something useful missing, let Brian Carroll know or add him as a reviewer on a PR.
|
||||
|
@ -4,7 +4,7 @@ Roc is a language for making delightful software. It does not have an 0.1 releas
|
||||
certainly don't recommend using it in production in its current state! However, it can be fun to
|
||||
play around with as long as you have a high tolerance for missing features and compiler bugs. :)
|
||||
|
||||
The [tutorial](../TUTORIAL.md) is the best place to learn about how to use the language - it assumes no prior knowledge of Roc or similar languages. (If you already know [Elm](https://elm-lang.org/), then [Roc for Elm Programmers](https://github.com/roc-lang/roc/blob/main/roc-for-elm-programmers.md) may be of interest.)
|
||||
The [tutorial](https://roc-lang.org/tutorial) is the best place to learn about how to use the language - it assumes no prior knowledge of Roc or similar languages. (If you already know [Elm](https://elm-lang.org/), then [Roc for Elm Programmers](https://github.com/roc-lang/roc/blob/main/roc-for-elm-programmers.md) may be of interest.)
|
||||
|
||||
There's also a folder of [examples](https://github.com/roc-lang/roc/tree/main/examples) - the [CLI form example](https://github.com/roc-lang/roc/tree/main/examples/cli/form.roc) in particular is a reasonable starting point to build on.
|
||||
|
||||
|
@ -1249,7 +1249,7 @@ If you put these into a hypothetical Roc REPL, here's what you'd see:
|
||||
- `comparable` is used in Elm for comparison operators (like `<` and such), plus `List.sort`, `Dict`, and `Set`. Roc's comparison operators (like `<`) only accept numbers; `"foo" < "bar"` is valid Elm, but will not compile in Roc. Roc's dictionaries and sets are hashmaps behind the scenes (rather than ordered trees), so their keys need to be hashable but not necessarily comparable.
|
||||
|
||||
That said, Roc's `Dict` and `Set` do have a restriction on their keys, just not `comparable`.
|
||||
See the section on Abilities in [the tutorial](TUTORIAL.md) for details.
|
||||
See the section on Abilities in [the tutorial](https://roc-lang.org/tutorial) for details.
|
||||
|
||||
## Standard library
|
||||
|
||||
|
@ -39,7 +39,7 @@
|
||||
<p>With all that context in mind, if you'd like to try it out or to get involved with contributing,
|
||||
the <a href="https://github.com/roc-lang/roc">source code repository</a> has
|
||||
<a href="https://github.com/roc-lang/roc/releases">nightly builds</a> you can download,
|
||||
and a <a href="https://github.com/roc-lang/roc/blob/main/TUTORIAL.md">tutorial</a>.</p>
|
||||
and a <a href="https://roc-lang.org/tutorial">tutorial</a>.</p>
|
||||
|
||||
<p>If you'd like to learn more about Roc, you can continue reading here, or check out one of these videos:</p>
|
||||
<ul>
|
||||
|
@ -40,12 +40,12 @@
|
||||
<li><a href="#booleans">Booleans</a></li>
|
||||
<li><a href="#lists">Lists</a></li>
|
||||
<li><a href="#types">Types</a></li>
|
||||
<li><a href="#crashing">Crashing</a></li>
|
||||
<li><a href="#tests-and-expectations">Tests and Expectations</a></li>
|
||||
<li><a href="#modules">Modules</a></li>
|
||||
<li><a href="#modules">Platforms and Packages</a></li>
|
||||
<li><a href="#tasks">Tasks</a></li>
|
||||
<li><a href="#abilities">Abilities</a></li>
|
||||
<li><a href="#next-steps">Next Steps</a></li>
|
||||
<li><a href="#advanced-concepts">Advanced Concepts</a></li>
|
||||
<li><a href="#operator-desugaring-table">Operator Desugaring Table</a></li>
|
||||
</ol>
|
||||
@ -504,6 +504,25 @@ inside a <code>when</code>, we would write <code>Custom r g b <span class="op">-
|
||||
<code>Custom description <span class="op">-></span> description</code> branch, <code>Custom description</code> would be a pattern. In programming, using
|
||||
patterns in branching conditionals like <code>when</code> is known as <a href="https://en.wikipedia.org/wiki/Pattern_matching">pattern matching</a>. You may hear people say things like "let's pattern match on <code>Custom</code> here" as a way to
|
||||
suggest making a <code>when</code> branch that begins with something like <code>Custom description <span class="op">-></span></code>.</p>
|
||||
<h3 id="pattern-matching-on-lists"><a href="#pattern-matching-on-lists">Pattern Matching on Lists</a></h3>
|
||||
<p>You can also pattern match on lists, like so:</p>
|
||||
<samp><span class="kw">when</span> myList <span class="kw">is</span>
|
||||
<span class="brace">[]</span> <span class="kw">-></span> <span class="number">0</span> <span class="comment"># the list is empty</span>
|
||||
<span class="brace">[</span>Foo<span class="comma">,</span> <span class="kw">..</span><span class="brace">]</span> <span class="kw">-></span> <span class="number">1</span> <span class="comment"># it starts with a Foo tag</span>
|
||||
<span class="brace">[</span>_<span class="comma">,</span> ..<span class="brace">]</span> <span class="kw">-></span> <span class="number">2</span> <span class="comment"># it contains at least one element, which we ignore</span>
|
||||
<span class="brace">[</span>Foo<span class="comma">,</span> Bar<span class="comma">,</span> ..<span class="brace">]</span> <span class="kw">-></span> <span class="number">3</span> <span class="comment"># it starts with a Foo tag followed by a Bar tag</span>
|
||||
<span class="brace">[</span>Foo<span class="comma">,</span> Bar<span class="comma">,</span> Baz<span class="brace">]</span> <span class="kw">-></span> <span class="number">4</span> <span class="comment"># it has exactly 3 elements: Foo, Bar, and Baz</span>
|
||||
<span class="brace">[</span>Foo<span class="comma">,</span> a<span class="comma">,</span> ..<span class="brace">]</span> <span class="kw">-></span> <span class="number">5</span> <span class="comment"># its first element is Foo, and its second we name `a`</span>
|
||||
<span class="brace">[</span>Ok a<span class="comma">,</span> ..<span class="brace">]</span> <span class="kw">-></span> <span class="number">6</span> <span class="comment"># it starts with an Ok containing a payload named `a`</span>
|
||||
<span class="brace">[</span>..<span class="comma">,</span> Foo<span class="brace">]</span> <span class="kw">-></span> <span class="number">7</span> <span class="comment"># it ends with a Foo tag</span>
|
||||
<span class="brace">[</span>A<span class="comma">,</span> B, <span class="kw">..</span><span class="comma">,</span> C<span class="comma">,</span> D<span class="brace">]</span> <span class="kw">-></span> <span class="number">8</span> <span class="comment"># it has certain elements at the beginning and end</span>
|
||||
</samp>
|
||||
<p>This can be both more concise and more efficient (at runtime) than calling <a href="https://www.roc-lang.org/builtins/List#get"><code>List.get</code></a>
|
||||
multiple times, since each call to <code>get</code> requires a separate conditional to handle the different
|
||||
<code>Result</code>s they return.</p>
|
||||
<blockquote>
|
||||
<p><strong>Note:</strong> Each list pattern can only have one <code>..</code>, which is known as the "rest pattern" because it's where the <em>rest</em> of the list goes.</p>
|
||||
</blockquote>
|
||||
<h2 id="booleans">Booleans</h2>
|
||||
<p>In many programming languages, <code>true</code> and <code>false</code> are special language keywords that refer to
|
||||
the two boolean values. In Roc, booleans do not get special keywords; instead, they are exposed
|
||||
@ -739,7 +758,7 @@ fullName <span class="op">=</span> <span class="str">\firstName,</span> lastName
|
||||
</samp>
|
||||
<p>Comments can be valuable documentation, but they can also get out of date and become misleading.
|
||||
If someone changes this function and forgets to update the comment, it will no longer be accurate.</p>
|
||||
<h3 id="type-annotations"><a href="#type-annotations">Type annotations</a></h3>
|
||||
<h3 id="type-annotations"><a href="#type-annotations">Type Annotations</a></h3>
|
||||
<p>Here's another way to document this function's type, which doesn't have that problem:</p>
|
||||
<samp>fullName : Str, Str <span class="op">-></span> Str
|
||||
fullName <span class="op">=</span> \firstName, lastName <span class="op">-></span>
|
||||
@ -765,6 +784,7 @@ amy <span class="op">=</span> { <span class="str">firstName:</span> <span class=
|
||||
<span class="str">jen :</span> { <span class="str">firstName :</span> Str, <span class="str">lastName :</span> Str }
|
||||
jen <span class="op">=</span> { <span class="str">firstName:</span> <span class="str">"Jen"</span>, <span class="str">lastName:</span> <span class="str">"Majura"</span> }
|
||||
</samp>
|
||||
<h3 id="type-aliases"><a href="#type-aliases">Type Aliases</a></h3>
|
||||
<p>When we have a recurring type annotation like this, it can be nice to give it its own name. We do this like
|
||||
so:</p>
|
||||
<samp><span class="str">Musician :</span> { <span class="str">firstName :</span> Str, <span class="str">lastName :</span> Str }
|
||||
@ -779,16 +799,8 @@ simone <span class="op">=</span> { <span class="str">firstName:</span> <span cla
|
||||
instead of to a value. Just like how you can read <code>name : Str</code> as "<code>name</code> has the type <code>Str</code>,"
|
||||
you can also read <code>Musician : { firstName : Str, lastName : Str }</code> as "<code>Musician</code> has the type
|
||||
<code>{ firstName : Str, lastName : Str }</code>."</p>
|
||||
<p>We can also give type annotations to tag unions:</p>
|
||||
<samp>colorFromStr : Str<span class="hljs-function"> <span class="op">-></span> [Red, Green, Yellow]
|
||||
colorFromStr <span class="op">=</span> <span class="str">\string</span> <span <span class="opclass="hljs-function">-><</span>/span>
|
||||
<span class="kw">when</span> string <span class="kw">is</span>
|
||||
<span class="str">"red"</span><span class="hljs-function"> <span class="op">-></span> Red
|
||||
<span class="str">"green"</span><span class="hljs-function"> <span class="op">-></span> Green
|
||||
_<span class="hljs-function"> <span class="op">-></span> Yellow
|
||||
</samp>
|
||||
<p>You can read the type <code>[Red, Green, Yellow]</code> as "a tag union of the tags <code>Red</code>, <code>Green</code>, and <code>Yellow</code>."</p>
|
||||
<p>When we annotate a list type, we have to specify the type of its elements:</p>
|
||||
<h3 id="type-parameters"><a href="#type-parameters">Type Parameters</a></h3>
|
||||
<p>Annotations for lists must specify what type the list's elements have:</p>
|
||||
<samp>names : List Str
|
||||
names <span class="op">=</span> [<span class="str">"Amy"</span>, <span class="str">"Simone"</span>, <span class="str">"Tarja"</span>]
|
||||
</samp>
|
||||
@ -796,6 +808,7 @@ names <span class="op">=</span> [<span class="str">"Amy"</span>, <span class="st
|
||||
<code>List</code> we're dealing with. <code>List</code> is a <em>parameterized type</em>, which means it's a type that requires a type
|
||||
parameter; there's no way to give something a type of <code>List</code> without a type parameter - you have to specify
|
||||
what type of list it is, such as <code>List Str</code> or <code>List Bool</code> or <code>List { firstName : Str, lastName : Str }</code>.</p>
|
||||
<h3 id="wildcard-type"><a href="#wildcard-type">Wildcard Types (*)</a></h3>
|
||||
<p>There are some functions that work on any list, regardless of its type parameter. For example, <code>List.isEmpty</code>
|
||||
has this type:</p>
|
||||
<samp>isEmpty : List * <span class="op">-></span> Bool
|
||||
@ -807,6 +820,7 @@ with any type of <code>List</code> - so, <code>List Str</code>, <code>List Bool<
|
||||
function that takes a <code>List Bool</code>. We might reasonably expect to be able to pass an empty list (that is, <code>[]</code>) to
|
||||
either of these functions. And so we can! This is because a <code>[]</code> value has the type <code>List *</code> - that is,
|
||||
"a list with a wildcard type parameter," or "a list whose element type could be anything."</p>
|
||||
<h3 id="type-variables"><a href="#type-variables">Type Variables</a></h3>
|
||||
<p><code>List.reverse</code> works similarly to <code>List.isEmpty</code>, but with an important distinction. As with <code>isEmpty</code>, we can
|
||||
call <code>List.reverse</code> on any list, regardless of its type parameter. However, consider these calls:</p>
|
||||
<samp><span class="kw">strings </span>: List <span class="kw">Str
|
||||
@ -840,6 +854,46 @@ of the type annotation, or even the function's implementation! The only way to h
|
||||
<code>List *</code> is if it returns an empty list.</p>
|
||||
<p>Similarly, the only way to have a function whose type is <code>a <span class="op">-></span> a</code> is if the function's implementation returns
|
||||
its argument without modifying it in any way. This is known as <a href="https://en.wikipedia.org/wiki/Identity_function">the identity function</a>.</p>
|
||||
<h3 id="tag-union-types"><a href="#tag-union-tyes">Tag Union Types</a></h3>
|
||||
<p>We can also annotate types that include tags:</p>
|
||||
<samp>colorFromStr : Str <span class="kw">-></span> <span class="brace">[</span>Red<span class="comma">,</span> Green<span class="comma">,</span> Yellow<span class="brace">]</span>
|
||||
colorFromStr <span class="kw">=</span> <span class="kw">\</span>string <span class="kw">-></span>
|
||||
<span class="kw">when</span> string <span class="kw">is</span>
|
||||
<span class="str">"red"</span> <span class="kw">-></span> Red
|
||||
<span class="str">"green"</span> <span class="kw">-></span> Green
|
||||
<span class="kw">_</span> <span class="kw">-></span> Yellow
|
||||
</samp>
|
||||
<p>You can read the type <code>[Red, Green, Yellow]</code> as "a tag union of the tags <code>Red</code>, <code>Green</code>, and <code>Yellow</code>."</p>
|
||||
<p>Some tag unions have only one tag in them. For example:</p>
|
||||
<samp>redTag <span class="kw">:</span> <span class="brace">[</span>Red<span class="brace">]</span>
|
||||
|
||||
redTag <span class="kw">=</span> Red
|
||||
</samp>
|
||||
<h3 id="accumulating-tag-types"><a href="#accumulating-tag-types">Accumulating Tag Types</a></h3>
|
||||
<p>Tag union types can accumulate more tags based on how they're used. Consider this <code>if</code> expression:</p>
|
||||
<samp><span class="kw">\</span>str <span class="kw">-></span>
|
||||
<span class="kw">if</span> Str.isEmpty str <span class="kw">then</span>
|
||||
Ok <span class="str">"it was empty"</span>
|
||||
<span class="kw">else</span>
|
||||
Err <span class="brace">[</span><span class="str">"it was not empty"</span><span class="brace">]</span>
|
||||
</samp>
|
||||
<p>Here, Roc sees that the first branch has the type <code>[Ok Str]</code> and that the <code>else</code> branch has
|
||||
the type <code>[Err (List Str)]</code>, so it concludes that the whole <code>if</code> expression evaluates to the
|
||||
combination of those two tag unions: <code>[Ok Str, Err (List Str)]</code>.</p>
|
||||
<p>This means this entire <code>\str -> …</code> function has the type <code>Str -> [Ok Str, Err (List Str)]</code>.
|
||||
However, it would be most common to annotate it as <code>Result Str (List Str)</code> instead, because
|
||||
the <code>Result</code> type (for operations like <code>Result.withDefault</code>, which we saw earlier) is a type
|
||||
alias for a tag union with <code>Ok</code> and <code>Err</code> tags that each have one payload:</p>
|
||||
<samp>Result ok err <span class="kw">:</span> <span class="brace">[</span>Ok ok<span class="comma">,</span> Err err<span class="brace">]</span>
|
||||
</samp>
|
||||
<p>We just saw how tag unions get combined when different branches of a conditional return different tags. Another way tag unions can get combined is through pattern matching. For example:</p>
|
||||
<samp><span class="kw">when</span> color <span class="kw">is</span>
|
||||
Red <span class="kw">-></span> <span class="str">"red"</span>
|
||||
Yellow <span class="kw">-></span> <span class="str">"yellow"</span>
|
||||
Green <span class="kw">-></span> <span class="str">"green"</span>
|
||||
</samp>
|
||||
<p>Here, Roc's compiler will infer that <code>color</code>'s type is <code>[Red, Yellow, Green]</code>, because
|
||||
those are the three possibilities this <code>when</code> handles.</p>
|
||||
<h2 id="numeric-types"><a href="#numeric-types">Numeric types</a></h2>
|
||||
<p>Roc has different numeric types that each have different tradeoffs.
|
||||
They can all be broken down into two categories: <a href="https://en.wikipedia.org/wiki/Fraction">fractions</a>,
|
||||
@ -1008,6 +1062,66 @@ so <code>0xC8u8</code> evaluates to decimal <code>200</code> as an unsigned 8-bi
|
||||
each bit. <code>0b0000_1000</code> evaluates to decimal <code>8</code>
|
||||
The integer type can be specified as a suffix to the binary literal,
|
||||
so <code>0b0100u8</code> evaluates to decimal <code>4</code> as an unsigned 8-bit integer.</p>
|
||||
<section><h2 id="crashing"><a href="#crashing">Crashing</a></h2>
|
||||
<p>Ideally, Roc programs would never crash. However, there are some situations where they may. For example:</p>
|
||||
<ol>
|
||||
<li>When doing normal integer arithmetic (e.g. <code>x + y</code>) that overflows.</li>
|
||||
<li>When the system runs out of memory.</li>
|
||||
<li>When a variable-length collection (like a <code>List</code> or <code>Str</code>) gets too
|
||||
long to be representible in the operating system's address space.
|
||||
(A 64-bit operating system's address space can represent several
|
||||
<a href="https://en.wikipedia.org/wiki/Byte#Multiple-byte_units">exibytes</a>
|
||||
of data, so this case should not come up often.)
|
||||
</li>
|
||||
</ol>
|
||||
<p>Crashes in Roc are not like
|
||||
<a href="https://en.wikipedia.org/wiki/Exception_handling">try/catch exceptions</a>
|
||||
found in some other programming languages. There is no way to "catch" a crash. It immediately
|
||||
ends the program, and what happens next is defined by the platform. (For example, a command-line
|
||||
interface platform might exit with a nonzero <a href="https://en.wikipedia.org/wiki/Exit_status">exit code</a>,
|
||||
whereas a web server platform might have the current request respond with a
|
||||
<a href="https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#500">HTTP 500 error</a>.)</p>
|
||||
<h3 id="crashing-in-unreachable-branches"><a href="#crashing-in-unreachable-branches">Crashing in unreachable branches</a></h3>
|
||||
<p>You can intentionally crash a Roc program, for example inside a conditional branch that
|
||||
you believe is unreachable. Suppose you're certain that a particular <code>List U8</code>
|
||||
contains valid UTF-8 bytes, which means when you call <code>Str.fromUtf8</code> on it, the
|
||||
<code>Result</code> it returns will always be <code>Ok</code>. In that scenario, you can use
|
||||
the <code>crash</code> keyword to handle the <code>Err</code> case like so:</p>
|
||||
<samp>answer : Str
|
||||
answer =
|
||||
<span class="kw">when</span> Str.fromUtf8 definitelyValidUtf8 <span class="kw">is</span>
|
||||
Ok str <span class="kw">-></span> str
|
||||
Err _ <span class="kw">-></span> <span class="kw">crash</span> <span class="str">"This should never happen!"</span>
|
||||
</samp>
|
||||
<p>If the unthinkable happens, and somehow the program reaches this <code>Err</code> branch even though that
|
||||
was thought to be impossible, then it will crash - just like if the system had run out of memory.
|
||||
The string passed to <code>crash</code> will be provided to the platform as context; each platform may do
|
||||
something different with it.</p>
|
||||
<blockquote>
|
||||
<p><b>Note:</b> <code>crash</code> is a language keyword and not a function; you can't assign <code>crash</code> to a variable
|
||||
or pass it to a function.</p>
|
||||
</blockquote>
|
||||
<h3 id="crashing-for-todos"><a href="#crashing-for-todos">Crashing for TODOs</a></h3>
|
||||
<p>Another use for <code>crash</code> is as a TODO marker when you're in the middle of building something:</p>
|
||||
<samp><span class="kw">if</span> x <span class="op">></span> y <span class="kw">then</span>
|
||||
transmogrify (x <span class="op">*</span> <span class="number">2</span>)
|
||||
<span class="kw">else</span>
|
||||
<span class="kw">crash</span> <span class="str">"TODO handle the x <= y case"</span>
|
||||
</samp>
|
||||
<p>This lets you do things like write tests for the non-<code>crash</code> branch, and then come back and finish
|
||||
the other branch later.</p>
|
||||
</section>
|
||||
<h3 id="crashing-for-error-handling"><a href="#crashing-for-error-handling">Crashing for error handling</a></h3>
|
||||
<p><code>crash</code> is not for error handling.</p>
|
||||
<p>The reason Roc has a <code>crash</code> keyword is for scenarios where it's expected that no error
|
||||
will ever happen (like in <a href="#crashing-in-unreachable-branches">unreachable branches</a>),
|
||||
or where graceful error handling is infeasible (like running out of memory).
|
||||
</p>
|
||||
<p>Errors that are recoverable should be represented using normal Roc types (
|
||||
like <code><a href="https://www.roc-lang.org/builtins/Result">Result</a></code>)
|
||||
and then handled without crashing—for example, by having the application
|
||||
report that something went wrong, and then continue running from there.
|
||||
</p>
|
||||
<h2 id="tests-and-expectations"><a href="#tests-and-expectations">Tests and expectations</a></h2>
|
||||
<p>You can write automated tests for your Roc code like so:</p>
|
||||
<samp>pluralize <span class="op">=</span> \singular, plural, count <span class="op">-></span>
|
||||
|
Loading…
Reference in New Issue
Block a user