mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Merge pull request #4718 from roc-lang/docs-faq
Update FAQ and some other docs
This commit is contained in:
commit
74b3d14277
3 changed files with 31 additions and 13 deletions
10
FAQ.md
10
FAQ.md
|
@ -140,7 +140,7 @@ and `Optional` (like in Java).
|
|||
By design, Roc does not have one of these. There are several reasons for this.
|
||||
|
||||
First, if a function returns a potential error, Roc has the convention to use `Result` with an error type that
|
||||
has a single tag describing what went wrong. (For example, `List.first : List a -> Result a [ListWasEmpty]*`
|
||||
has a single tag describing what went wrong. (For example, `List.first : List a -> Result a [ListWasEmpty]`
|
||||
instead of `List.first : List a -> Maybe a`.) This is not only more self-descriptive, it also composes better with
|
||||
other operations that can fail; there's no need to have functions like `Result.toMaybe` or `Maybe.toResult`,
|
||||
because in Roc, the convention is that operations that can fail always use `Result`.
|
||||
|
@ -170,7 +170,7 @@ for using `Maybe` even when it's less self-descriptive), we'd have to rewrite al
|
|||
helper functions. As such, a subtle downside of these helper functions is that they discourage any change to
|
||||
the data model that would break their call sites, even if that change would improve the data model overall.
|
||||
|
||||
On a historical note, `Maybe` may have been thought of as a substitute for null references—as opposed to something that emerged organically based on specific motivating use cases after `Result` already existed. That said, in languages that do not have an equivalent of Roc's tag unions, it's much less ergonomic to write something like `Result a [ListWasEmpty]*`, so that design would not fit those languages as well as it fits Roc.
|
||||
On a historical note, `Maybe` may have been thought of as a substitute for null references—as opposed to something that emerged organically based on specific motivating use cases after `Result` already existed. That said, in languages that do not have an equivalent of Roc's tag unions, it's much less ergonomic to write something like `Result a [ListWasEmpty]`, so that design would not fit those languages as well as it fits Roc.
|
||||
|
||||
## Why doesn't Roc have higher-kinded polymorphism or arbitrary-rank types?
|
||||
|
||||
|
@ -204,9 +204,7 @@ No implementation of Rank-2 types can remove any of these downsides. Thus far, w
|
|||
with sufficiently nice APIs that only require Rank-1 types, and we haven't seen a really compelling use case
|
||||
where the gap between the Rank-2 and Rank-1 designs was big enough to justify switching to Rank-2.
|
||||
|
||||
Since I prefer Roc being simpler and having a faster compiler with nicer error messages, my hope is that Roc
|
||||
will never get Rank-2 types. However, it may turn out that in the future we learn about currently-unknown
|
||||
upsides that somehow outweigh these downsides, so I'm open to considering the possibility - while rooting against it.
|
||||
As such, the plan is for Roc to stick with Rank-1 types indefinitely. In Roc's case, the benefits of Rank-1's faster compilation with nicer error messages and a simpler type system outweigh Rank-2's benefits of expanded API options.
|
||||
|
||||
### Higher-kinded polymorphism
|
||||
|
||||
|
@ -289,8 +287,6 @@ Roc also has a different standard library from Elm. Some of the differences come
|
|||
- `Str` instead of `String` - after using the `str` type in Rust, I realized I had no issue whatsoever with the more concise name, especially since it was used in so many places (similar to `Msg` and `Cmd` in Elm) - so I decided to save a couple of letters.
|
||||
- No function composition operators - I stopped using these in Elm so long ago, at one point I forgot they were in the language! See the FAQ entry on currying for details about why.
|
||||
- No `Char`. What most people think of as a "character" is a rendered glyph. However, rendered glyphs are comprised of [grapheme clusters](https://stackoverflow.com/a/27331885), which are a variable number of Unicode code points - and there's no upper bound on how many code points there can be in a single cluster. In a world of emoji, I think this makes `Char` error-prone and it's better to have `Str` be the only first-class unit. For convenience when working with unicode code points (e.g. for performance-critical tasks like parsing), the single-quote syntax is sugar for the corresponding `U32` code point - for example, writing `'鹏'` is exactly the same as writing `40527`. Like Rust, you get a compiler error if you put something in single quotes that's not a valid [Unicode scalar value](http://www.unicode.org/glossary/#unicode_scalar_value).
|
||||
- No `Debug.log` - the editor can do a better job at this, or you can write `expect x != x` to see what `x` is when the expectation fails. Using the editor means your code doesn't change, and using `expect` gives a natural reminder to remove the debugging code before shipping: the build will fail.
|
||||
- No `Debug.todo` - instead you can write a type annotation with no implementation below it; the type checker will treat it normally, but attempting to use the value will cause a runtime exception. This is a feature I've often wanted in Elm, because I like prototyping APIs by writing out the types only, but then when I want the compiler to type-check them for me, I end up having to add `Debug.todo` in various places.
|
||||
- No `Maybe`. See the "Why doesn't Roc have a `Maybe`/`Option`/`Optional` type" FAQ question
|
||||
|
||||
## Why aren't Roc functions curried by default?
|
||||
|
|
|
@ -637,13 +637,26 @@ mapWithIndexHelp = \src, dest, func, index, length ->
|
|||
else
|
||||
dest
|
||||
|
||||
## Returns a list of all the integers from start to end.
|
||||
## The start is inclusive if it use `At x` and exclusive if it uses `After x`.
|
||||
## The end is inclusive if it use `At x` and exclusive if it uses `Before x`.
|
||||
## If end is `Length x`, the final list will contain x elements.
|
||||
## If step is specified, the values are incremented by step.
|
||||
## Returns a list of all the integers between `start` and `end`.
|
||||
##
|
||||
## >>> List.range { start: At 2, end: Before 8, step: 3 }
|
||||
## To include the `start` and `end` integers themselves, use `At` like so:
|
||||
##
|
||||
## List.range { start: At 2, end: At 5 } # returns [2, 3, 4, 5]
|
||||
##
|
||||
## To exclude them, use `After` and `Before`, like so:
|
||||
##
|
||||
## List.range { start: After 2, end: Before 5 } # returns [3, 4]
|
||||
##
|
||||
## You can have the list end at a certain length rather than a certain integer:
|
||||
##
|
||||
## List.range { start: At 6, end: Length 4 } # returns [6, 7, 8, 9]
|
||||
##
|
||||
## If `step` is specified, each integer increases by that much. (`step: 1` is the default.)
|
||||
##
|
||||
## List.range { start: After 1, end: Before 10, step: 3 } # returns [2, 5, 8]
|
||||
##
|
||||
## All of these options are compatible with the others. For example, you can use `At` or `After`
|
||||
## with `start` regardless of what `end` and `step` are set to.
|
||||
# TODO: Make the type annotation work
|
||||
# range :
|
||||
# {
|
||||
|
|
|
@ -1240,6 +1240,14 @@ If you put these into a hypothetical Roc REPL, here's what you'd see:
|
|||
28 : Int *
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Instead of a separate testing tool, Roc has a built-in `expect` keyword, which
|
||||
you can use in conjunction with `roc test` to run tests.
|
||||
|
||||
See [the tutorial section on testing](https://www.roc-lang.org/tutorial#tests-and-expectations)
|
||||
for details.
|
||||
|
||||
## Abilities
|
||||
|
||||
`comparable`, `appendable`, and `number` don't exist in Roc.
|
||||
|
@ -1299,6 +1307,7 @@ Some differences to note:
|
|||
- No `Tuple`. Roc doesn't have tuple syntax. As a convention, `Pair` can be used to represent tuples (e.g. `List.zip : List a, List b -> List [Pair a b]*`), but this comes up infrequently compared to languages that have dedicated syntax for it.
|
||||
- No `Task`. By design, platform authors implement `Task` (or don't; it's up to them) - it's not something that really *could* be usefully present in Roc's standard library.
|
||||
- No `Process`, `Platform`, `Cmd`, or `Sub` - similarly to `Task`, these are things platform authors would include, or not.
|
||||
- No `Debug`. Roc has a [built-in `dbg` keyword](https://www.roc-lang.org/tutorial#debugging) instead of `Debug.log` and a [`crash` keyword](https://www.roc-lang.org/tutorial#crashing) instead of `Debug.todo`.
|
||||
- No `Maybe`. This is by design. If a function returns a potential error, use `Result` with an error type that uses a zero-arg tag to describe what went wrong. (For example, `List.first : List a -> Result a [ListWasEmpty]*` instead of `List.first : List a -> Maybe a`.) If you want to have a record field be optional, use an Optional Record Field directly (see earlier). If you want to describe something that's neither an operation that can fail nor an optional field, use a more descriptive tag - e.g. for a nullable JSON decoder, instead of `nullable : Decoder a -> Decoder (Maybe a)`, make a self-documenting API like `nullable : Decoder a -> Decoder [Null, NonNull a]*`.
|
||||
|
||||
## Operator Desugaring Table
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue