on master help sign in
Shuffle docs around
commitd87788f27d0c817cb949c72f18ccd2d4e271a28a authorEvan Czaplicki <evancz@users.noreply.github.com> dateWed 18 Apr 2018, 11:12 (9 years ago) parent42028aa
16 files changed−1087
docs/ContributorAgreement.pdf → ContributorAgreement.pdf docs/hints/bad-recursion.md−135 docs/hints/effect-modules.md−10 docs/hints/implicit-casts.md−53 docs/hints/import-cycles.md−184 docs/hints/imports.md−125 docs/hints/infinite-type.md−116 docs/hints/missing-patterns.md−142 docs/hints/port-modules.md−32 docs/hints/recursive-alias.md−161 docs/hints/shadowing.md−69 docs/hints/type-annotations.md−60 docs/upgrade/0.16.md → upgrade-docs/0.16.md docs/upgrade/0.17.md → upgrade-docs/0.17.md docs/upgrade/0.18.md → upgrade-docs/0.18.md docs/upgrade/earlier.md → upgrade-docs/earlier.md
docs/ContributorAgreement.pdf → ContributorAgreement.pdfrenamed

Binary file not shown.

docs/hints/bad-recursion.mddeleted−135
@@ -1,135 +0,0 @@
1−# Hints for Bad Recursion
2−
3−There are two problems that will lead you here, both of them pretty tricky:
4−
5− 1. [**No Mutation**](#no-mutation) &mdash; Defining values in Elm is slightly different than defining values in languages like JavaScript.
6−
7− 2. [**Tricky Recursion**](#tricky-recursion) &mdash; Sometimes you need to define recursive values. A common case is JSON decoders for things like discussion forums, where a comment may have replies, which may have replies, etc.
8−
9−
10−## No Mutation
11−
12−Languages like JavaScript let you “reassign” variables. When you say `x = x + 1` it means: whatever `x` was pointing to, have it point to `x + 1` instead. This called *mutating* a variable. All values are immutable in Elm, so reassigning variables does not make any sense! Okay, so what *should* `x = x + 1` mean in Elm?
13−
14−Well, what does it mean with functions? In Elm, we write recursive functions like this:
15−
16−```elm
17−factorial : Int -> Int
18−factorial n =
19− if n <= 0 then 1 else n * factorial (n - 1)
20−```
21−
22−One cool thing about Elm is that whenever you see `factorial 3`, you can always replace that expression with `if 3 <= 0 then 1 else 3 * factorial (3 - 1)` and it will work exactly the same. So when Elm code gets evaluated, we will keep expanding `factorial` until the `if` produces a 1. At that point, we are done expanding and move on.
23−
24−The thing that surprises newcomers is that recursion works the same way with values too. So take the following definition:
25−
26−```elm
27−x = x + 1
28−```
29−
30−We are actually defining `x` in terms of itself. So it would expand out to `x = ... + 1 + 1 + 1 + 1`, trying to add one to `x` an infinite number of times! This means your program would just run forever, endlessly expanding `x`. In practice, this means the page freezes and the computer starts to get kind of warm. No good! We can detect cases like this with the compiler, so we give an error at compile time so this does not happen in the wild.
31−
32−The fix is usually to just give the new value a new name. So you could rewrite it to:
33−
34−```elm
35−x1 = x + 1
36−```
37−
38−Now `x` is the old value and `x1` is the new value. Again, one cool thing about Elm is that whenever you see a `factorial 3` you can safely replace it with its definition. Well, the same is true of values. Wherever I see `x1`, I can replace it with `x + 1`. Thanks to the way definitions work in Elm, this is always safe!
39−
40−
41−## Tricky Recursion
42−
43−Now, there are some cases where you *do* want a recursive value. Say you are building a website with comments and replies. You may define a comment like this:
44−
45−```elm
46−type alias Comment =
47− { message : String
48− , upvotes : Int
49− , downvotes : Int
50− , responses : Responses
51− }
52−
53−type Responses = Responses (List Comment)
54−```
55−
56−You may have run into this definition in the [hints for recursive aliases](recursive-alias.md)! Anyway, once you have comments, you may want to turn them into JSON to send back to your server or to store in your database or whatever. So you will probably write some code like this:
57−
58−```elm
59−import Json.Decode as Decode exposing (Decoder)
60−
61−decodeComment : Decoder Comment
62−decodeComment =
63− Decode.map4 Comment
64− (Decode.field "message" Decode.string)
65− (Decode.field "upvotes" Decode.int)
66− (Decode.field "downvotes" Decode.int)
67− (Decode.field "responses" decodeResponses)
68−
69−-- PROBLEM
70−decodeResponses : Decoder Responses
71−decodeResponses =
72− Decode.map Responses (Decode.list decodeComment)
73−```
74−
75−The problem is that now `decodeComment` is defined in terms of itself! To know what `decodeComment` is, I need to expand `decodeResponses`. To know what `decodeResponses` is, I need to expand `decodeComment`. This loop will repeat endlessly!
76−
77−In this case, the trick is to use `Json.Decode.lazy` which delays the evaluation of a decoder until it is needed. So the valid definition would look like this:
78−
79−```elm
80−import Json.Decode as Decode exposing (Decoder)
81−
82−decodeComment : Decoder Comment
83−decodeComment =
84− Decode.map4 Comment
85− (Decode.field "message" Decode.string)
86− (Decode.field "upvotes" Decode.int)
87− (Decode.field "downvotes" Decode.int)
88− (Decode.field "responses" decodeResponses)
89−
90−-- SOLUTION
91−decodeResponses : Decoder Responses
92−decodeResponses =
93− Decode.map Responses (Decode.list (Decode.lazy (\_ -> decodeComment)))
94−```
95−
96−Notice that in `decodeResponses`, we hide `decodeComment` behind an anonymous function. Elm cannot evaluate an anonymous function until it is given arguments. So it allows us to delay evaluation until it is needed. If there are no comments, we will not need to expand it!
97−
98−
99−### Summary
100−
101−**Situation:** You want a recursive JSON decoder, random value generator, or task. These are all cases where a *value* represents some sort of computation.
102−
103−**Solution:** put the recursion behind an anonymous function.
104−
105−You can always do this by defining `lazy` in terms of `andThen`. In the case of random value generators, it would look like this:
106−
107−```elm
108−import Random exposing (Generator, andThen)
109−import Random.Extra exposing (constant)
110−
111−lazy : (() -> Generator a) -> Generator a
112−lazy delayedGenerator =
113− constant ()
114− |> andThen delayedGenerator
115−```
116−
117−If you are in some situation where this will not work, I am curious to hear about it. I would recommend asking around in [the Elm slack](http://elmlang.herokuapp.com/) first, and opening an issue here if it seems to be the real deal!
118−
119−
120−## Defining “Bad” Recursion
121−
122−The compiler will yell at you for *bad* recursion, but how does it know the difference between good and bad situations? Writing `factorial` is fine, but writing `x = x + 1` is not. One version of `decodeComment` was bad, but the other was fine. What is the rule?
123−
124−**Elm will allow recursive definitions as long as there is at least one lambda before you get back to yourself.** So if we write `factorial` without any pretty syntax, it looks like this:
125−
126−```elm
127−factorial =
128− \n -> if n <= 0 then 1 else n * factorial (n - 1)
129−```
130−
131−There is technically a lambda between the definition and the use! The same is true with the good version of `decodeComment`. As long as there is a lambda before you get back to yourself, the compiler will let it through.
132−
133−This rule is nice, but it does not catch *everything*. Pathological cases like `x = (\_ -> x) () + 1` can make it through. Why not rule these out as well though?! Well, because it is impossible! And not the normal kind of impossible where your cable bill is messed up and the fifth time you call it turns out it *can* be corrected. This is the &ldquo;we proved it with math, it’s called [the halting problem](https://en.wikipedia.org/wiki/Halting_problem)&rdquo; kind of impossible. Impossible [like this](https://www.youtube.com/watch?v=nlD9JYP8u5E).
134−
135−Anyway, I just thought it was cool that we cannot solve the halting problem *in general*, but a simple rule about lambdas can detect the majority of bad cases *in practice*.
docs/hints/effect-modules.mddeleted−10
@@ -1,10 +0,0 @@
1−
2−# Reviewing Effect Modules
3−
4−Effect modules in the package ecosystem define “The Elm Platform”, providing nice APIs for things like web sockets, geolocation, and page visibility.
5−
6−The only intent of effect modules is to help Elm communicate with **external** services. If you want to write a wrapper around GraphQL or Phoenix Channels, you are using effect modules as intended. If you are doing any other kind of thing, it may be subverting “The Elm Platform” in relatively serious ways.
7−
8−So to *publish* a package that uses effect modules, you need to go through a review process to make sure these facilities are not being abused. Think of it as contributing to the compiler or core libraries. Obviously someone is going to review that PR in those cases. Same thing here.
9−
10−To make this as smooth as possible, discuss it [on slack](http://elmlang.herokuapp.com/) and [the elm-dev mailing list](https://groups.google.com/forum/#!forum/elm-dev) as soon as possible. It is impossible to collaborate with people if you do not communicate! So come and talk through your goals. See if it aligns with Elm overall or if there is some nicer way.
docs/hints/implicit-casts.mddeleted−53
@@ -1,53 +0,0 @@
1−
2−# Implicit Casts
3−
4−Many languages automatically convert from `Int` to `Float` when they think it is necessary. This conversion is often called an [implicit cast](https://en.wikipedia.org/wiki/Type_conversion).
5−
6−Languages that will add in implicit casts for addition include:
7−
8− - JavaScript
9− - Python
10− - Ruby
11− - C
12− - C++
13− - C#
14− - Java
15− - Scala
16−
17−These languages generally agree that an `Int` may be implicitly cast to a `Float` when necessary. So everyone is doing it, why not Elm?!
18−
19−> **Note:** Ruby does not follow the trend. They implicitly cast a `Float` to an `Int`, truncating all the decimal points!
20−
21−
22−## Type Inference + Implicit Casts
23−
24−Elm comes from the ML-family of languages. Languages in the ML-family that **never** do implicit casts include:
25−
26− - Standard ML
27− - OCaml
28− - Elm
29− - F#
30− - Haskell
31−
32−Why would so many languages from this lineage require explicit conversions though?
33−
34−Well, we have to go back to the 1970s for some background. J. Roger Hindley and Robin Milner independently discovered an algorithm that could _efficiently_ figure out the type of everything in your program without any type annotations. Type Inference! Every ML-family language has some variation of this algorithm at the center of its design.
35−
36−For decades, the problem was that nobody could figure out how to combine type inference with implicit casts AND make the resulting algorithm efficient enough for daily use. As far as I know, Scala was the first widely known language to figure out how to combine these two things! Its creator, Martin Odersky did a lot of work on combining type inference and subtyping to make this possible.
37−
38−So for any ML-family language designed before Scala, it is safe to assume that implicit conversions just was not an option. Okay, but what about Elm?! It comes after Scala, so why not do it like them?!
39−
40− 1. You pay performance cost to mix type inference and implicit conversions. At least as far as anyone knows, it defeats an optimization that is crucial to getting _reliably_ good performance. It is fine in most cases, but it can be a real issue in very large code bases.
41−
42− 2. Based on experience reports from Scala users, it seemed like the convenience was not worth the hidden cost. Yes, you can convert `n` in `(n + 1.5)` and everything is nice, but when you are in larger programs that are sparsely annotated, it can be quite difficult to figure out what is going on.
43−
44−This user data may be confounded by the fact that Scala allows quite extensive conversions, not just from `Int` to `Float`, but I think it is worth taking seriously nonetheless. So it is _possible_, but it is has tradeoffs.
45−
46−
47−## Conclusion
48−
49−First, based on the landscape of design possibilities, it seems like requiring _explicit_ conversions is a pretty nice balance. We can have type inference, it can produce friendly error messages, the algorithm is snappy, and an unintended implicit cast will not flow hundreds of lines before manifesting to the user.
50−
51−Second, Elm very much favors explicit code, so this also fits in with the overall spirit of the language and libraries.
52−
53−I hope that clarifies why you have to add those `toFloat` and `round` functions! It definitely can take some getting used to, but there are tons of folks who get past that acclimation period and really love the tradeoffs!
docs/hints/import-cycles.mddeleted−184
@@ -1,184 +0,0 @@
1−
2−# Import Cycles
3−
4−What is an import cycle? In practice you may see it if you create two modules with interrelated `User` and `Comment` types like this:
5−
6−```elm
7−module Comment exposing (..)
8−
9−import User
10−
11−type alias Comment =
12− { comment : String
13− , author : User.User
14− }
15−```
16−
17−```elm
18−module User exposing (..)
19−
20−import Comment
21−
22−type alias User =
23− { name : String
24− , comments : List Comment.Comment
25− }
26−```
27−
28−Notice that to compile `Comment` we need to `import User`. And notice that to compile `User` we need to `import Comment`. We need both to compile either!
29−
30−Now this is *possible* if the compiler figures out any module cycles and puts them all in one big file to compile them together. That seems fine in our small example, but imagine we have a cycle of 20 modules. If you change *one* of them, you must now recompile *all* of them. In a large code base, this causes extremely long compile times. It is also very hard to disentangle them in practice, so you just end up with slow builds. That is your life now.
31−
32−The thing is that you can always write the code *without* cycles by shuffling declarations around, and the resulting code is often much clearer.
33−
34−
35−# How to Break Cycles
36−
37−There are quite a few ways to break our `Comment` and `User` cycle from above, so let’s go through four useful strategies. The first one is by far the most common solution!
38−
39−
40−## 1. Combine the Modules
41−
42−One approach is to just combine the two modules. If we check out the resulting code, we have actually revealed a problem in how we are representing our data:
43−
44−```elm
45−module BadCombination1 exposing (..)
46−
47−type alias Comment =
48− { comment : String
49− , author : User
50− }
51−
52−type alias User =
53− { name : String
54− , comments : List Comment
55− }
56−```
57−
58−Notice that the `Comment` type alias is defined in terms of the `User` type alias and vice versa. Having recursive type aliases like this does not work! That problem is described in depth [here](recursive-alias.md), but the quick takeaway is that one `type alias` needs to become a `type` to break the recursion. So let’s try again:
59−
60−```elm
61−module BadCombination2 exposing (..)
62−
63−type alias Comment =
64− { comment : String
65− , author : User
66− }
67−
68−type alias User =
69− { name : String
70− , comments : AllUserComments
71− }
72−
73−type AllUserComments = AllUserComments (List Comment)
74−```
75−
76−Okay, now we have broken the recursion, but we need to ask ourselves, how are we going to actually instantiate these `Comment` and `User` types that we have described. A `Comment` will always have an author, and that `User` will always refer back to the `Comment`. So we seem to want cyclic data here. If we were in JavaScript we might instantiate all the comments in one pass, and then go back through and mutate the users to point to all the relevant comments. In other words, we need *mutation* to create this cyclic data!
77−
78−All values are immutable in Elm, so we need to use a more functional strategy. One common approach is to use unique identifiers. Instead of referring directly to “the user object” we can refer to a user ID:
79−
80−```elm
81−module GoodCombination exposing (..)
82−
83−import Dict
84−
85−type alias Comment =
86− { comment : String
87− , author : UserId
88− }
89−
90−type alias UserId = String
91−
92−type alias AllComments =
93− Dict.Dict UserId (List Comment)
94−```
95−
96−Now in this world, we do not even have cycles in our types anymore! That means we can actually break these out into separate modules again:
97−
98−```elm
99−module Comment exposing (..)
100−
101−import Dict
102−import User
103−
104−type alias Comment =
105− { comment : String
106− , author : User.Id
107− }
108−
109−type alias AllComments =
110− Dict.Dict User.Id (List Comment)
111−```
112−
113−```elm
114−module User exposing (..)
115−
116−type alias Id = String
117−```
118−
119−So now we are back to the two modules we wanted, but we have data structures that are going to work much better in a functional language like Elm! **This is the common approach, and it is what you hope will happen!**
120−
121−
122−## 2. Make a New Module
123−
124−Now say there are actually a ton of functions and values in the `Comment` and `User` modules. Combining them into one does not seem like a good strategy. Instead you can create a *third* module that just has the shared types and functions. Let’s pretend we call that third module `GoodCombination`. So rather than having `Comment` and `User` depend on each other, they now both depend on `GoodCombination`. We broke our cycle!
125−
126−**This strategy is less common.** You generally want to keep the core `type` of a module with all the functions that act upon it directly, so separating a `type` from everything else is a bad sign. So maybe there is a `User` module that contains a bunch of helper functions, but you *use* all those helper functions in a bunch of other modules that interact with users in various ways. In that scenario, it is still more sophisticated than “just throw the types in a module together” and hope it turns out alright.
127−
128−
129−## 3. Use Type Variables
130−
131−Another way to avoid module cycles is to be more generic in how you represent your data:
132−
133−```elm
134−module Comment exposing (..)
135−
136−type alias Comment author =
137− { comment : String
138− , author : author
139− }
140−```
141−
142−```elm
143−module User exposing (..)
144−
145−type alias User comment =
146− { name : String
147− , comments : List comment
148− }
149−```
150−
151−Notice that `Comment` and `User` no longer need to import each other! Instead, whenever we use these modules, we need to fill in the type variable. So we may import both `Comment` and `User` and try to combine them into a `Comment (User (Comment (User ...)))`. Gah, we ran into the recursive type alias thing again!
152−
153−So this strategy fails pretty badly with our particular example. The code is more complicated and it still does not work! So **this strategy is rarely useful**, but when it works, it can simplify things quite a lot.
154−
155−
156−## 4. Hiding Implementation Details in Packages
157−
158−This gets a little bit trickier when you are creating a package like `elm-lang/parser` which is built around the `Parser` type.
159−
160−That package has a couple exposed modules: `Parser`, `Parser.LanguageKit`, and `Parser.LowLevel`. All of these modules want access to the internal details of the `Parser` type, but we do not want to ever expose those internal details to the *users* of this package. So where should the `Parser` type live?!
161−
162−Usually you know which module should expose the type for the best public API. In this case, it makes sense for it to live in the `Parser` module. The way to manage this is to create a `Parser.Internal` module with a definition like:
163−
164−```elm
165−module Parser.Internal exposing (..)
166−
167−type Parser a =
168− Parser ...
169−```
170−
171−Now we can `import Parser.Internal` and use it in any of the modules in our package. The trick is that we never expose the `Parser.Internal` module to the *users* of our package. We can see what is inside, but they cannot! Then in the `Parser` module we can say:
172−
173−```elm
174−module Parser exposing (..)
175−
176−import Parser.Internal as Internal
177−
178−type alias Parser a =
179− Internal.Parser a
180−```
181−
182−So now folks see a `Parser` type exposed by the `Parser` module, and it is the one that is used throughout all the modules in the package. Do not screw up your data representation to avoid this trick! I think we can improve how this appears in documentation, but overall this is the best way to go.
183−
184−Now again, this strategy is particularly useful in packages. It is not as worthwhile in application code.
docs/hints/imports.mddeleted−125
@@ -1,125 +0,0 @@
1−# Hints for Imports
2−
3−When getting started with Elm, it is pretty common to have questions about how the `import` declarations work exactly. These questions usually arise when you start playing with the `Html` library so we will focus on that.
4−
5−
6−<br>
7−
8−## `import`
9−
10−An Elm file is called a **module**. To access code in other files, you need to `import` it!
11−
12−So say you want to use the [`div`](http://package.elm-lang.org/packages/elm-lang/html/latest/Html#div) function from the [`elm-lang/html`](http://package.elm-lang.org/packages/elm-lang/html/latest) package. The simplest way is to import it like this:
13−
14−```elm
15−import Html
16−
17−main =
18− Html.div [] []
19−```
20−
21−After saying `import Html` we can refer to anything inside that module as long as it is *qualified*. This works for:
22−
23− - **Values** &mdash; we can refer to `Html.text`, `Html.h1`, etc.
24− - **Types** &mdash; We can refer to [`Attribute`](http://package.elm-lang.org/packages/elm-lang/html/latest/Html#Attribute) as `Html.Attribute`.
25−
26−So if we add a type annotation to `main` it would look like this:
27−
28−```elm
29−import Html
30−
31−main : Html.Html msg
32−main =
33− Html.div [] []
34−```
35−
36−We are referring to the [`Html`](http://package.elm-lang.org/packages/elm-lang/html/latest/Html#Html) type, using its *qualified* name `Html.Html`. This can feel weird at first, but it starts feeling natural quite quickly!
37−
38−> **Note:** Modules do not contain other modules. So the `Html` module *does not* contain the `Html.Attributes` module. Those are separate names that happen to have some overlap. So if you say `import Html` you *do not* get access to `Html.Attributes.style`. You must `import Html.Attributes` module separately.
39−
40−
41−<br>
42−
43−## `as`
44−
45−It is best practice to always use *qualified* names, but sometimes module names are so long that it becomes unwieldy. This is common for the `Html.Attributes` module. We can use the `as` keyword to help with this:
46−
47−```elm
48−import Html
49−import Html.Attributes as A
50−
51−main =
52− Html.div [ A.style "color" "red" ] [ Html.text "Hello!" ]
53−```
54−
55−Saying `import Html.Attributes as A` lets us refer to any value or type in `Html.Attributes` as long as it is qualified with an `A`. So now we can refer to [`style`](http://package.elm-lang.org/packages/elm-lang/html/latest/Html-Attributes#style) as `A.style`.
56−
57−
58−<br>
59−
60−## `exposing`
61−
62−In quick drafts, maybe you want to use *unqualified* names. You can do that with the `exposing` keyword like this:
63−
64−```elm
65−import Html exposing (..)
66−import Html.Attributes exposing (style)
67−
68−main : Html msg
69−main =
70− div [ style "color" "red" ] [ text "Hello!" ]
71−```
72−
73−Saying `import Html exposing (..)` means I can refer to any value or type from the `Html` module without qualification. Notice that I use the `Html` type, the `div` function, and the `text` function without qualification in the example above.
74−
75−> **Note:** It seems neat to expose types and values directly, but it can get out of hand. Say you `import` ten modules `exposing` all of their content. It quickly becomes difficult to figure out what is going on in your code. “Wait, where is this function from?” And then trying to sort through all the imports to find it. Point is, use `exposing (..)` sparingly!
76−
77−Saying `import Html.Attributes exposing (style)` is a bit more reasonable. It means I can refer to the `style` function without qualification, but that is it. You are still importing the `Html.Attributes` module like normal though, so you would say `Html.Attributes.class` or `Html.Attributes.id` to refer to other values and types from that module.
78−
79−
80−<br>
81−
82−## `as` and `exposing`
83−
84−There is one last way to import a module. You can combine `as` and `exposing` to try to get a nice balance of qualified names:
85−
86−```elm
87−import Html exposing (Html, div, text)
88−import Html.Attributes as A exposing (style)
89−
90−main : Html msg
91−main =
92− div [ A.class "greeting", style "color" "red" ] [ text "Hello!" ]
93−```
94−
95−Notice that I refer to `A.class` which is qualified and `style` which is unqualified.
96−
97−
98−<br>
99−
100−## Default Imports
101−
102−We just learned all the variations of the `import` syntax in Elm. You will use some version of that syntax to `import` any module you ever write.
103−
104−It would be the best policy to make it so every module in the whole ecosystem works this way. We thought so in the past at least, but there are some modules that are so commonly used that the Elm compiler automatically adds the imports to every file. These default imports include:
105−
106−```elm
107−import Basics exposing (..)
108−import List exposing ( List, (::) )
109−import Maybe exposing ( Maybe( Just, Nothing ) )
110−import Result exposing ( Result( Ok, Err ) )
111−import String
112−import Tuple
113−
114−import Debug
115−
116−import Platform exposing ( Program )
117−import Platform.Cmd as Cmd exposing ( Cmd )
118−import Platform.Sub as Sub exposing ( Sub )
119−```
120−
121−You can think of these imports being at the top of any module you write.
122−
123−One could argue that `Maybe` is so fundamental to how we handle errors in Elm code that it is *basically* part of the language. One could also argue that it is extraordinarily annoying to have to import `Maybe` once you get past your first couple weeks with Elm. Either way, we know that default imports are not ideal in some sense, so we have tried to keep the default imports as minimal as possible.
124−
125−> **Note:** Elm performs dead code elimination, so if you do not use something from a module, it is not included in the generated code. So if you `import` a module with hundreds of functions, you do not need to worry about the size of your assets. You will only get what you use!
docs/hints/infinite-type.mddeleted−116
@@ -1,116 +0,0 @@
1−# Hints for Infinite Types
2−
3−Infinite types are probably the trickiest kind of bugs to track down. Usually it means you are working on a relatively sophisticated recursive function and something is very subtly off.
4−
5−I am just going to show a couple examples of infinite types that have been reported and how they were resolved to illustrate the kinds of things you may be running into.
6−
7−
8−## Nested Record Types
9−
10−(From issue [#987](https://github.com/elm-lang/elm-compiler/issues/987))
11−
12−Someone was working with records, and wanted to do something kind of tricky with type aliases. In this case, they created a `Persisted` type alias that would say "whatever record you have, well I'm talking about one where there is an additional `id` field."
13−
14−```elm
15−type alias Persisted record =
16− { record | id : Int }
17−
18−type alias Update record =
19− record -> Int -> record
20−
21−type Updatable record =
22− Updatable (Update record) (Persisted record)
23−
24−newRecord (Updatable myUpdate myRecord) =
25− let
26− updateThisRecord =
27− myUpdate myRecord
28− in
29− "foo"
30−```
31−
32−Now just looking at the code, it seems fine. You can create `Persisted` records, you can have a record `Update`, and you can bundle them together with `Updatable`. In our `newRecord` function we are partially applying the `myUpdate` function. Everything *seems* fine, but something is causing an infinite type.
33−
34−The best thing to do is start writing down as many types for yourself as possible:
35−
36−```elm
37−myUpdate : Update record -- record -> Int -> record
38−myRecord : Persisted record -- { record | id : Int }
39−```
40−
41−The trouble is that it's the same `record` in both of these types! The `myUpdate` function wants to take a `record` and produce a `record`, but it is being given `{ record | id : Int }`. Type checking is going to say, "well, if `record` is actually an infinite sequence of `{ { ... | id : Int } | id : Int }` then they *can* be equal!" While that is true and very clever, it is not the intent of this code.
42−
43−So the fix for this person was to add one thing into the `Updatable` type:
44−
45−```elm
46−type Updatable record =
47− Updatable (Update (Persisted record)) (Persisted record)
48−```
49−
50−Notice the new `Persisted` in the `Update` part. That was the fix!
51−
52−
53−## Exploding Either
54−
55−(From issue [#707](https://github.com/elm-lang/elm-compiler/issues/707))
56−
57−There is a relatively obscure package called `evancz/automaton` that captures state and functionality using callbacks. So far, it does not seem to be extremely useful idea given its downsides, but it did lead to quite a tough infinite type.
58−
59−Here is a snippet of code that combines two basic automatons into one. The resulting automaton takes in either a `Left` or `Right` value. If it is a `Left` we will use the left automaton, if it is a `Right` we will use the right one.
60−
61−```elm
62−type Either a b = Left a | Right b
63−
64−type Automaton a b =
65− Step (a -> (Automaton a b, b))
66−
67−(+++) : Automaton a b -> Automaton c d -> Automaton (Either a c) (Either b d)
68−(+++) (Step leftStep) (Step rightStep) =
69− Step <| \either ->
70− case either of
71− Left a ->
72− let (newLeft, b) = leftStep a
73− in (newLeft, Left b)
74−
75− Right c ->
76− let (newRight, d) = rightStep c
77− in (newRight, Right d)
78−```
79−
80−This triggers a relatively confusing error message. The right thing to do in these scenarios is try to figure out the type of literally every piece of the definition. If you can, break parts out into other top-level declarations with type annotations so the compiler can check your work. So you might write down some notes to yourself like this:
81−
82−```elm
83−left : Automaton a b
84−leftStep : a -> (Automaton a b, b)
85−
86−right : Automaton c d
87−rightStep : c -> (Automaton c d, d)
88−
89−either : Either a c
90−
91−newLeft : Automaton a b
92−newRight : Automaton c d
93−```
94−
95−Knowing that both branches of a `case` must end with the same type, it looks like `newLeft` and `newRight` are causing the issue here. So in the revised code we make it so both branches return the same type.
96−
97−```elm
98−type Either a b = Left a | Right b
99−
100−type Automaton a b =
101− Step (a -> (Automaton a b, b))
102−
103−(+++) : Automaton a b -> Automaton c d -> Automaton (Either a c) (Either b d)
104−(+++) (Step leftStep as left) (Step rightStep as right) =
105− Step <| \either ->
106− case either of
107− Left a ->
108− let (newLeft, b) = leftStep a
109− in (newLeft +++ right, Left b)
110−
111− Right c ->
112− let (newRight, d) = rightStep c
113− in (left +++ newRight, Right d)
114−```
115−
116−So yeah, if you are skimming this, you probably did not see the change immediately. My experience debugging these kinds of things is that my brain thinks what I wrote is correct so much that it becomes kind of blind to the issue. The best thing to do is slow down and break the problem apart. Or ask someone.
docs/hints/missing-patterns.mddeleted−142
@@ -1,142 +0,0 @@
1−# Hints for Missing Patterns
2−
3−Elm checks to make sure that all possible inputs to a function or `case` are handled. This gives us the guarantee that no Elm code is ever going to crash because data had an unexpected shape.
4−
5−There are a couple techniques for making this work for you in every scenario.
6−
7−
8−## The danger of wildcard patterns
9−
10−A common scenario is that you want to add a tag to a union type that is used in a bunch of places. For example, maybe you are working with some widgets:
11−
12−```elm
13−type Widget
14− = ScatterPlot ...
15− | Table ...
16−
17−
18−isGraph : Widget -> Bool
19−isGraph widget =
20− case widget of
21− ScatterPlot _ ->
22− True
23−
24− _ ->
25− False
26−```
27−
28−Notice the wildcard pattern in `isGraph`. This will hurt us! When you add `BarChart` as a new kind of `Widget` you are introducing a bug that the compiler cannot catch. A `BarChart` is a graph, but the code deciding that is just lumping a bunch of stuff together.
29−
30−It is better to explicitly list all possible patterns, like this:
31−
32−```elm
33−isGraph : Widget -> Bool
34−isGraph widget =
35− case widget of
36− ScatterPlot _ ->
37− True
38−
39− Table _ ->
40− False
41−```
42−
43−So now when you want to add `BarChart`, the compiler will say "hey, what should `isGraph` do when it sees a bar chart?" This is a tiny bit of extra work, but it is very worth it!
44−
45−
46−## I want to go fast!
47−
48−Okay, so we are still editing that `Widget` code. We are not using any dangerous wildcards anymore, but there are 20 or 30 functions all pattern matching on `Widget` and doing something.
49−
50−```elm
51−type Widget
52− = ScatterPlot ...
53− | Table ...
54−
55−
56−isGraph : Widget -> Bool
57−isGraph widget =
58− case widget of
59− ScatterPlot _ ->
60− True
61−
62− Table _ ->
63− False
64−
65−
66−-- and maybe a bunch of other things
67−```
68−
69−So now you add a new tag `BarChart` to `Widget`. This will trigger errors in all the functions that pattern match on widgets. In a big project, maybe this is a ton of functions.
70−
71−To get things running quickly, it can be helpful to use [`Debug.crash`](http://package.elm-lang.org/packages/elm-lang/core/latest/Debug#crash) temporarily. So you might update the code to this:
72−
73−```elm
74−type Widget
75− = ScatterPlot ...
76− | Table ...
77− | BarChart ...
78−
79−
80−isGraph : Widget -> Bool
81−isGraph widget =
82− case widget of
83− ScatterPlot _ ->
84− True
85−
86− Table _ ->
87− False
88−
89− BarChart _ ->
90− Debug.crash "TODO"
91−
92−
93−-- and maybe a bunch of other things
94−```
95−
96−Rather than figure out the exact details, just put in `Debug.crash "TODO"` for now. The Elm compiler is actually aware of `Debug.crash` so when it sees it in a `case` like this, it will augment the crash message with a bunch of helpful information. It will tell you:
97−
98− 1. The name of the module that contains the offending code.
99− 2. The line numbers of the `case` containing the crash.
100− 3. The particular value that led to this crashing branch.
101−
102−From that information you have a pretty good idea of what went wrong and can go fix it.
103−
104−I tend to use `TODO` as the message when my goal is to go quick because it makes it easy to go and find all remaining todos in my code before a release.
105−
106−> And in 99.999% of cases, a `Debug.crash` should never make it to a release. It is nice for debugging (like it says in the name) but it is not really a good idea to use it in other ways. When you hit a `Debug.crash` the program really does crash. It is just done working.
107−
108−
109−## A list that definitely is not empty
110−
111−This can come up from time to time, but Elm **will not** let you write code like this:
112−
113−```elm
114−last : List a -> a
115−last list =
116− case list of
117− [x] ->
118− x
119−
120− _ :: rest ->
121− last rest
122−```
123−
124−This is no good. It does not handle the empty list. The recommended definition would be:
125−
126−```elm
127−last : List a -> Maybe a
128−last list =
129− case list of
130− [] ->
131− Nothing
132−
133− [x] ->
134− Just x
135−
136− _ :: rest ->
137− last rest
138−```
139−
140−This is nice because it lets users know that there might be a failure, so they can recover from it however they want.
141−
142−> An alternative would be to represent a non-empty list explicitly. For example, the type `(a, List a)` guarantees that there is at least one `a` value, so you could alternatively create a function `last : (a, List a) -> a` or `last : a -> List a -> a` to demand at least one item.
docs/hints/port-modules.mddeleted−32
@@ -1,32 +0,0 @@
1−
2−# No Ports in Packages
3−
4−The package ecosystem is one of the most important parts of Elm. Right now, our ecosystem has some compelling benefits:
5−
6− - There are many obvious default packages that work well.
7− - Adding dependencies cannot introduce runtime exceptions.
8− - Patch changes cannot lead to surprise build failures.
9−
10−These are really important factors if you want to *quickly* create *reliable* applications. The Elm community thinks this is valuable.
11−
12−Other communities think that the *number* of packages is a better measure of ecosystem health. That is a fine metric to use, but it is not the one we use for Elm. We would rather have 50 great packages than 100k packages of wildly varying quality.
13−
14−
15−## So what about ports?
16−
17−Imagine you install a new package that claims to support `localStorage`. You get it set up, working through any compile errors. You run it, but it does not seem to work! After trying to figure it out for hours, you realize there is some poorly documented `port` to hook up...
18−
19−Okay, now you need to hook up some JavaScript code. Is that JS file in the Elm package? Or is it on `npm`? Wait, what version on `npm` though? And is this patch version going to work as well? Also, how does this file fit into my build process? And assuming we get through all that, maybe the `port` has the same name as one of the ports in your project. Or it clashes with a `port` name in another package.
20−
21−**Suddenly adding dependencies is much more complicated and risky!** An experienced developer would always check for ports up front, spending a bunch of time manually classifying unacceptable packages. Most people would not know to do that and learn all the pitfalls through personal experience, ultimately spending even *more* time than the person who defensively checks to avoid these issues.
22−
23−So “ports in packages” would impose an enormous cost on application developers, and in the end, we would have a less reliable package ecosystem overall.
24−
25−
26−## Conclusion
27−
28−Our wager with the Elm package ecosystem is that it is better to get a package *right* than to get it *right now*. So while we could use “ports in packages” as a way to get twenty `localStorage` packages of varying quality *right now*, we are choosing not to go that route. Instead we ask that developers use ports directly in their application code, getting the same result a different way.
29−
30−Now this may not be the right choice for your particular project, and that is okay! We will be expanding our core libraries over time, as explained [here](https://github.com/elm-lang/projects/blob/master/roadmap.md#where-is-the-localstorage-package), and we hope you will circle back later to see if Elm has grown into a better fit!
31−
32−If you have more questions about this choice or what it means for your application, please come ask in [the Elm slack](http://elmlang.herokuapp.com/). Folks are friendly and happy to help out! Chances are that a `port` in your application will work great for your case once you learn more about how they are meant to be used.
docs/hints/recursive-alias.mddeleted−161
@@ -1,161 +0,0 @@
1−# Hints for Recursive Type Aliases
2−
3−At the root of this issue is the distinction between a `type` and a `type alias`.
4−
5−
6−## What is a type alias?
7−
8−When you create a type alias, you are just creating a shorthand to refer to an existing type. So when you say the following:
9−
10−```elm
11−type alias Time = Float
12−
13−type alias Degree = Float
14−
15−type alias Weight = Float
16−```
17−
18−You have not created any *new* types, you just made some alternate names for `Float`. You can write down things like this and it'll work fine:
19−
20−```elm
21−add : Time -> Degree -> Weight
22−add time degree =
23− time + degree
24−```
25−
26−This is kind of a weird way to use type aliases though. The typical usage would be for records, where you do not want to write out the whole thing every time. Stuff like this:
27−
28−```elm
29−type alias Person =
30− { name : String
31− , age : Int
32− , height : Float
33− }
34−```
35−
36−It is much easier to write down `Person` in a type, and then it will just expand out to the underlying type when the compiler checks the program.
37−
38−
39−## Recursive type aliases?
40−
41−Okay, so lets say you have some type that may contain itself. In Elm, a common example of this is a comment that might have subcomments:
42−
43−```elm
44−type alias Comment =
45− { message : String
46− , upvotes : Int
47− , downvotes : Int
48− , responses : List Comment
49− }
50−```
51−
52−Now remember that type *aliases* are just alternate names for the real type. So to make `Comment` into a concrete type, the compiler would start expanding it out.
53−
54−```elm
55− { message : String
56− , upvotes : Int
57− , downvotes : Int
58− , responses :
59− List
60− { message : String
61− , upvotes : Int
62− , downvotes : Int
63− , responses :
64− List
65− { message : String
66− , upvotes : Int
67− , downvotes : Int
68− , responses : List ...
69− }
70− }
71− }
72−```
73−
74−The compiler cannot deal with values like this. It would just keep expanding forever.
75−
76−
77−## Recursive types!
78−
79−In cases where you want a recursive type, you need to actually create a brand new type. This is what the `type` keyword is for. A simple example of this can be seen when defining a linked list:
80−
81−```elm
82−type List
83− = Empty
84− | Node Int List
85−```
86−
87−No matter what, the type of `Node n xs` is going to be `List`. There is no expansion to be done. This means you can represent recursive structures with types that do not explode into infinity.
88−
89−So let's return to wanting to represent a `Comment` that may have responses. There are a couple ways to do this:
90−
91−
92−### Obvious, but kind of annoying
93−
94−```elm
95−type Comment =
96− Comment
97− { message : String
98− , upvotes : Int
99− , downvotes : Int
100− , responses : List Comment
101− }
102−```
103−
104−Now lets say you want to register an upvote on a comment:
105−
106−```elm
107−upvote : Comment -> Comment
108−upvote (Comment comment) =
109− Comment { comment | upvotes = 1 + comment.upvotes }
110−```
111−
112−It is kind of annoying that we now have to unwrap and wrap the record to do anything with it.
113−
114−
115−### Less obvious, but nicer
116−
117−```elm
118−type alias Comment =
119− { message : String
120− , upvotes : Int
121− , downvotes : Int
122− , responses : Responses
123− }
124−
125−type Responses = Responses (List Comment)
126−```
127−
128−In this world, we introduce the `Responses` type to capture the recursion, but `Comment` is still an alias for a record. This means the `upvote` function looks nice again:
129−
130−```elm
131−upvote : Comment -> Comment
132−upvote comment =
133− { comment | upvotes = 1 + comment.upvotes }
134−```
135−
136−So rather than having to unwrap a `Comment` to do *anything* to it, you only have to do some unwrapping in the cases where you are doing something recursive. In practice, this means you will do less unwrapping which is nice.
137−
138−
139−## Mutually recursive type aliases
140−
141−It is also possible to build type aliases that are *mutually* recursive. That might be something like this:
142−
143−```elm
144−type alias Comment =
145− { message : String
146− , upvotes : Int
147− , downvotes : Int
148− , responses : Responses
149− }
150−
151−type alias Responses =
152− { sortBy : SortBy
153− , responses : List Comment
154− }
155−
156−type SortBy = Time | Score | MostResponses
157−```
158−
159−When you try to expand `Comment` you have to expand `Responses` which needs to expand `Comment` which needs to expand `Responses`, etc.
160−
161−So this is just a fancy case of a self-recursive type alias. The solution is the same. Somewhere in that cycle, you need to define an actual `type` to end the infinite expansion.
docs/hints/shadowing.mddeleted−69
@@ -1,69 +0,0 @@
1−# Variable Shadowing
2−
3−Variable shadowing is when you define the same variable name twice in an ambiguous way. Here is a pretty reasonable use of shadowing:
4−
5−```elm
6−viewName : Maybe String -> Html msg
7−viewName name =
8− case name of
9− Nothing ->
10− ...
11−
12− Just name ->
13− ...
14−```
15−
16−I define a `name` with type `Maybe String` and then in that second branch, I define a `name` that is a `String`. Now that there are two `name` values, it is not 100% obvious which one you want in that second branch.
17−
18−Most linters produce warnings on variable shadowing, so Elm makes “best practices” the default. Just rename the first one to `maybeName` and move on.
19−
20−This choice is relatively uncommon in programming languages though, so I want to provide the reasoning behind it.
21−
22−
23−## The Cost of Shadowing
24−
25−The code snippet from above is the best case scenario for variable shadowing. It is pretty clear really. But that is because it is a fake example. It does not even compile.
26−
27−In a large module that is evolving over time, this is going to cause bugs in a very predictable way. You will have two definitions, separated by hundreds of lines. For example:
28−
29−```elm
30−name : String
31−name =
32− "Tom"
33−
34−-- hundreds of lines
35−
36−viewName : String -> Html msg
37−viewName name =
38− ... name ... name ... name ...
39−```
40−
41−Okay, so the `viewName` function has an argument `name` and it uses it three times. Maybe the `viewName` function is 50 lines long in total, so those uses are not totally easy to see. This is fine so far, but say your colleague comes along five months later and wants to support first and last names. They refactor the code like this:
42−
43−```elm
44−viewName : String -> String -> Html msg
45−viewName firstName lastName =
46− ... name ... name ... name ...
47−```
48−
49−The code compiles, but it does not work as intended. They forgot to change all the uses of `name`, and because it shadows the top-level `name` value, it always shows up as `"Tom"`. It is a simple mistake, but it is always the last thing I think of.
50−
51−> Is the data being fetched properly? Let me log all of the JSON requests. Maybe the JSON decoders are messed up? Hmm. Maybe someone is transforming the name in a bad way at some point? Let me check my `update` code.
52−
53−Basically, a bunch of time gets wasted on something that could easily be detected by the compiler. But this bug is rare, right?
54−
55−
56−## Aggregate Cost
57−
58−Thinking of a unique and helpful name takes some extra time. Maybe 30 seconds. But it means that:
59−
60− 1. Your code is easier to read and understand later on. So you spend 30 seconds once `O(1)` rather than spending 10 seconds each time someone reads that code in the future `O(n)`.
61−
62− 2. The tricky shadowing bug described above is impossible. Say there is a 5% chance that any given edit produces a shadowing bug, and that resolving that shadowing bug takes one hour. That means the expected time for each edit increases by three minutes.
63−
64−If you are still skeptical, I encourage you can play around with the number of edits, time costs, and probabilities here. When shadowing is not allowed, the resulting overhead for the entire lifetime of the code is the 30 seconds it takes to pick a better name, so that is what you need to beat!
65−
66−
67−## Summary
68−
69−Without shadowing, the code easier to read and folks spend less time on pointless debugging. The net outcome is that folks have more time to make something wonderful with Elm!
docs/hints/type-annotations.mddeleted−60
@@ -1,60 +0,0 @@
1−# Hints for Type Annotation Problems
2−
3−At the root of this kind of issue is always the fact that a type annotation in your code does not match the corresponding definition. Now that may mean that the type annotation is "wrong" or it may mean that the definition is "wrong". The compiler cannot figure out your intent, only that there is some mismatch.
4−
5−This document is going to outline the various things that can go wrong and show some examples.
6−
7−
8−## Annotation vs. Definition
9−
10−The most common issue is with user-defined type variables that are too general. So lets say you have defined a function like this:
11−
12−```elm
13−addPair : (a, a) -> a
14−addPair (x, y) =
15− x + y
16−```
17−
18−The issue is that the type annotation is saying "I will accept a tuple containing literally *anything*" but the definition is using `(+)` which requires things to be numbers. So the compiler is going to infer that the true type of the definition is this:
19−
20−```elm
21−addPair : (number, number) -> number
22−```
23−
24−So you will probably see an error saying "I cannot match `a` with `number`" which is essentially saying, you are trying to provide a type annotation that is **too general**. You are saying `addPair` accepts anything, but in fact, it can only handle numbers.
25−
26−In cases like this, you want to go with whatever the compiler inferred. It is good at figuring this kind of stuff out ;)
27−
28−
29−## Annotation vs. Itself
30−
31−It is also possible to have a type annotation that clashes with itself. This is probably more rare, but someone will run into it eventually. Let's use another version of `addPair` with problems:
32−
33−```elm
34−addPair : (Int, Int) -> number
35−addPair (x, y) =
36− x + y
37−```
38−
39−In this case the annotation says we should get a `number` out, but because we were specific about the inputs being `Int`, the output should also be an `Int`.
40−
41−
42−## Annotation vs. Internal Annotation
43−
44−A quite tricky case is when an outer type annotation clashes with an inner type annotation. Here is an example of this:
45−
46−```elm
47−filter : (a -> Bool) -> List a -> List a
48−filter isOkay list =
49− let
50− keepIfOkay : a -> Maybe a
51− keepIfOkay x =
52− if isOkay x then Just x else Nothing
53− in
54− List.filterMap keepIfOkay list
55−```
56−
57−This case is very unfortunate because all the type annotations are correct, but there is a detail of how type inference works right now that **user-defined type variables are not shared between annotations**. This can lead to probably the worst type error messages we have because the problem here is that `a` in the outer annotation does not equal `a` in the inner annotation.
58−
59−For now the best route is to leave off the inner annotation. It is unfortunate, and hopefully we will be able to do a nicer thing in future releases.
60−
docs/upgrade/0.16.md → upgrade-docs/0.16.mdrenamed

The content is the same.

docs/upgrade/0.17.md → upgrade-docs/0.17.mdrenamed

The content is the same.

docs/upgrade/0.18.md → upgrade-docs/0.18.mdrenamed

The content is the same.

docs/upgrade/earlier.md → upgrade-docs/earlier.mdrenamed

The content is the same.