forked from roc-lang/roc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
375 additions
and
376 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -233,8 +233,8 @@ addAndStringify = \num1, num2 -> | |
|
||
We did two things here: | ||
|
||
* We introduced a local def named `sum`, and set it equal to `num1 + num2`. Because we defined `sum` inside `addAndStringify`, it will not be accessible outside that function. | ||
* We added an `if` / `then` / `else` conditional to return either `""` or `Num.toStr sum` depending on whether `sum == 0`. | ||
- We introduced a local def named `sum`, and set it equal to `num1 + num2`. Because we defined `sum` inside `addAndStringify`, it will not be accessible outside that function. | ||
- We added an `if` / `then` / `else` conditional to return either `""` or `Num.toStr sum` depending on whether `sum == 0`. | ||
|
||
Of note, we couldn't have done `total = num1 + num2` because that would be | ||
redefining `total` in the global scope, and defs can't be redefined. (However, we could use the name | ||
|
@@ -401,8 +401,8 @@ fromOriginal = { original & birds: 4, iguanas: 3 } | |
The `fromScratch` and `fromOriginal` records are equal, although they're assembled in | ||
different ways. | ||
|
||
* `fromScratch` was built using the same record syntax we've been using up to this point. | ||
* `fromOriginal` created a new record using the contents of `original` as defaults for fields that it didn't specify after the `&`. | ||
- `fromScratch` was built using the same record syntax we've been using up to this point. | ||
- `fromOriginal` created a new record using the contents of `original` as defaults for fields that it didn't specify after the `&`. | ||
|
||
Note that when we do this, the fields you're overriding must all be present on the original record, | ||
and their values must have the same type as the corresponding values in the original record. | ||
|
@@ -1093,9 +1093,9 @@ the lowest `U16` would be zero (since it always is for unsigned integers), and t | |
|
||
Choosing a size depends on your performance needs and the range of numbers you want to represent. Consider: | ||
|
||
* Larger integer sizes can represent a wider range of numbers. If you absolutely need to represent numbers in a certain range, make sure to pick an integer size that can hold them! | ||
* Smaller integer sizes take up less memory. These savings rarely matters in variables and function arguments, but the sizes of integers that you use in data structures can add up. This can also affect whether those data structures fit in [cache lines](https://en.wikipedia.org/wiki/CPU_cache#Cache_performance), which can easily be a performance bottleneck. | ||
* Certain processors work faster on some numeric sizes than others. There isn't even a general rule like "larger numeric sizes run slower" (or the reverse, for that matter) that applies to all processors. In fact, if the CPU is taking too long to run numeric calculations, you may find a performance improvement by experimenting with numeric sizes that are larger than otherwise necessary. However, in practice, doing this typically degrades overall performance, so be careful to measure properly! | ||
- Larger integer sizes can represent a wider range of numbers. If you absolutely need to represent numbers in a certain range, make sure to pick an integer size that can hold them! | ||
- Smaller integer sizes take up less memory. These savings rarely matters in variables and function arguments, but the sizes of integers that you use in data structures can add up. This can also affect whether those data structures fit in [cache lines](https://en.wikipedia.org/wiki/CPU_cache#Cache_performance), which can easily be a performance bottleneck. | ||
- Certain processors work faster on some numeric sizes than others. There isn't even a general rule like "larger numeric sizes run slower" (or the reverse, for that matter) that applies to all processors. In fact, if the CPU is taking too long to run numeric calculations, you may find a performance improvement by experimenting with numeric sizes that are larger than otherwise necessary. However, in practice, doing this typically degrades overall performance, so be careful to measure properly! | ||
|
||
Here are the different fixed-size integer types that Roc supports: | ||
|
||
|
@@ -1136,9 +1136,9 @@ As such, it's very important to design your integer operations not to exceed the | |
|
||
Roc has three fractional types: | ||
|
||
* `F32`, a 32-bit [floating-point number](https://en.wikipedia.org/wiki/IEEE_754) | ||
* `F64`, a 64-bit [floating-point number](https://en.wikipedia.org/wiki/IEEE_754) | ||
* `Dec`, a 128-bit decimal [fixed-point number](https://en.wikipedia.org/wiki/Fixed-point_arithmetic) | ||
- `F32`, a 32-bit [floating-point number](https://en.wikipedia.org/wiki/IEEE_754) | ||
- `F64`, a 64-bit [floating-point number](https://en.wikipedia.org/wiki/IEEE_754) | ||
- `Dec`, a 128-bit decimal [fixed-point number](https://en.wikipedia.org/wiki/Fixed-point_arithmetic) | ||
|
||
These are different from integers in that they can represent numbers with fractional components, | ||
such as 1.5 and -0.123. | ||
|
@@ -1248,8 +1248,8 @@ Roc compiler. That's why they're called "builtins!" | |
|
||
Besides being built into the compiler, the builtin modules are different from other modules in that: | ||
|
||
* They are always imported. You never need to add them to `imports`. | ||
* All their types are imported unqualified automatically. So you never need to write `Num.Nat`, because it's as if the `Num` module was imported using `imports [Num.{ Nat }]` (and the same for all the other types in the `Num` module). | ||
- They are always imported. You never need to add them to `imports`. | ||
- All their types are imported unqualified automatically. So you never need to write `Num.Nat`, because it's as if the `Num` module was imported using `imports [Num.{ Nat }]` (and the same for all the other types in the `Num` module). | ||
|
||
## The app module header | ||
|
||
|
@@ -1315,10 +1315,10 @@ platforms. Let's use the CLI platform in `examples/interactive/cli-platform/main | |
|
||
In the CLI platform, we have four operations we can do: | ||
|
||
* Write a string to the console | ||
* Read a string from user input | ||
* Write a string to a file | ||
* Read a string from a file | ||
- Write a string to the console | ||
- Read a string from user input | ||
- Write a string to a file | ||
- Read a string from a file | ||
|
||
We'll use these four operations to learn about tasks. | ||
|
||
|
@@ -1531,9 +1531,9 @@ This way, it reads like a series of instructions: | |
|
||
Some important things to note about backpassing and `await`: | ||
|
||
* `await` is not a language keyword in Roc! It's referring to the `Task.await` function, which we imported unqualified by writing `Task.{ await }` in our module imports. (That said, it is playing a similar role here to the `await` keyword in languages that have `async`/`await` keywords, even though in this case it's a function instead of a special keyword.) | ||
* Backpassing syntax does not need to be used with `await` in particular. It can be used with any function. | ||
* Roc's compiler treats functions defined with backpassing exactly the same way as functions defined the other way. The only difference between `\text ->` and `text <-` is how they look, so feel free to use whichever looks nicer to you! | ||
- `await` is not a language keyword in Roc! It's referring to the `Task.await` function, which we imported unqualified by writing `Task.{ await }` in our module imports. (That said, it is playing a similar role here to the `await` keyword in languages that have `async`/`await` keywords, even though in this case it's a function instead of a special keyword.) | ||
- Backpassing syntax does not need to be used with `await` in particular. It can be used with any function. | ||
- Roc's compiler treats functions defined with backpassing exactly the same way as functions defined the other way. The only difference between `\text ->` and `text <-` is how they look, so feel free to use whichever looks nicer to you! | ||
|
||
## Appendix: Advanced Concepts | ||
|
||
|
@@ -1555,9 +1555,9 @@ I can pass this function a record that has more fields than just | |
`firstName` and `lastName`, as long as it has *at least* both of those fields | ||
(and both of them are strings). So any of these calls would work: | ||
|
||
* `fullName { firstName: "Sam", lastName: "Sample" }` | ||
* `fullName { firstName: "Sam", lastName: "Sample", email: "[email protected]" }` | ||
* `fullName { age: 5, firstName: "Sam", things: 3, lastName: "Sample", role: Admin }` | ||
- `fullName { firstName: "Sam", lastName: "Sample" }` | ||
- `fullName { firstName: "Sam", lastName: "Sample", email: "[email protected]" }` | ||
- `fullName { age: 5, firstName: "Sam", things: 3, lastName: "Sample", role: Admin }` | ||
|
||
This `user` argument is an *open record* - that is, a description of a minimum set of fields | ||
on a record, and their types. When a function takes an open record as an argument, | ||
|
@@ -1611,9 +1611,9 @@ addHttps = \record -> | |
|
||
This function uses *constrained records* in its type. The annotation is saying: | ||
|
||
* This function takes a record which has at least a `url` field, and possibly others | ||
* That `url` field has the type `Str` | ||
* It returns a record of exactly the same type as the one it was given | ||
- This function takes a record which has at least a `url` field, and possibly others | ||
- That `url` field has the type `Str` | ||
- It returns a record of exactly the same type as the one it was given | ||
|
||
So if we give this function a record with five fields, it will return a record with those | ||
same five fields. The only requirement is that one of those fields must be `url : Str`. | ||
|
@@ -1850,14 +1850,14 @@ the tags in the open union you're providing. | |
|
||
So if I have an `[Ok Str]*` value, I can pass it to functions with any of these types (among others): | ||
|
||
* `[Ok Str]* -> Bool` | ||
* `[Ok Str] -> Bool` | ||
* `[Ok Str, Err Bool]* -> Bool` | ||
* `[Ok Str, Err Bool] -> Bool` | ||
* `[Ok Str, Err Bool, Whatever]* -> Bool` | ||
* `[Ok Str, Err Bool, Whatever] -> Bool` | ||
* `Result Str Bool -> Bool` | ||
* `[Err Bool, Whatever]* -> Bool` | ||
- `[Ok Str]* -> Bool` | ||
- `[Ok Str] -> Bool` | ||
- `[Ok Str, Err Bool]* -> Bool` | ||
- `[Ok Str, Err Bool] -> Bool` | ||
- `[Ok Str, Err Bool, Whatever]* -> Bool` | ||
- `[Ok Str, Err Bool, Whatever] -> Bool` | ||
- `Result Str Bool -> Bool` | ||
- `[Err Bool, Whatever]* -> Bool` | ||
|
||
That last one works because a function accepting an open union can accept any unrecognized tag, including | ||
`Ok Str` - even though it is not mentioned as one of the tags in `[Err Bool, Whatever]*`! Remember, when | ||
|
@@ -1881,10 +1881,10 @@ a catch-all `_ ->` branch, it might not know what to do with an `Ok Str` if it r | |
In summary, here's a way to think about the difference between open unions in a value you have, compared to a value you're accepting: | ||
|
||
* If you *have* a closed union, that means it has all the tags it ever will, and can't accumulate more. | ||
* If you *have* an open union, that means it can accumulate more tags through conditional branches. | ||
* If you *accept* a closed union, that means you only have to handle the possibilities listed in the union. | ||
* If you *accept* an open union, that means you have to handle the possibility that it has a tag you can't know about. | ||
- If you *have* a closed union, that means it has all the tags it ever will, and can't accumulate more. | ||
- If you *have* an open union, that means it can accumulate more tags through conditional branches. | ||
- If you *accept* a closed union, that means you only have to handle the possibilities listed in the union. | ||
- If you *accept* an open union, that means you have to handle the possibility that it has a tag you can't know about. | ||
|
||
### Type Variables in Tag Unions | ||
|
||
|
@@ -1932,8 +1932,8 @@ the `Foo Str` and `Bar Bool` we already know about). | |
If we removed the type annotation from `example` above, Roc's compiler would infer the same type anyway. | ||
This may be surprising if you look closely at the body of the function, because: | ||
|
||
* The return type includes `Foo Str`, but no branch explicitly returns `Foo`. Couldn't the return type be `[Bar Bool]a` instead? | ||
* The argument type includes `Bar Bool` even though we never look at `Bar`'s payload. Couldn't the argument type be inferred to be `Bar *` instead of `Bar Bool`, since we never look at it? | ||
- The return type includes `Foo Str`, but no branch explicitly returns `Foo`. Couldn't the return type be `[Bar Bool]a` instead? | ||
- The argument type includes `Bar Bool` even though we never look at `Bar`'s payload. Couldn't the argument type be inferred to be `Bar *` instead of `Bar Bool`, since we never look at it? | ||
|
||
The reason it has this type is the `other -> other` branch. Take a look at that branch, and ask this question: | ||
"What is the type of `other`?" There has to be exactly one answer! It can't be the case that `other` has one | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.