16 |
--------------------------------------------------------------------------------
/_sass/_custom.scss:
--------------------------------------------------------------------------------
1 | .precedence {
2 | td { padding: .5em; border-right: 1px solid lightgrey; }
3 | tr { margin: 0; padding: 0; }
4 | border-collapse: collapse;
5 | }
6 |
7 | table.task-conversions {
8 | margin-bottom: 2em;
9 | border-top: 1px solid lightgrey;
10 | border-bottom: 1px solid lightgrey;
11 | code {
12 | font-size: 80%;
13 | }
14 | td {
15 | padding-top: 1em;
16 | padding-bottom: 1em;
17 | }
18 | }
19 |
20 | input.filter {
21 | margin-bottom: 1em;
22 | margin-left: 3em;
23 | }
24 |
25 | ul.section-list {
26 | list-style-type: none;
27 | li { padding-top: 1em; }
28 | }
29 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | # Site settings
2 | title: Elm (language) FAQ
3 | description: > # this means to ignore newlines until "baseurl:"
4 | Unofficial FAQ for the Elm language.
5 | #baseurl: "/elm-faq" # the subpath of your site, e.g. /blog/
6 | #url: "http://yourdomain.com" # the base hostname & protocol for your site
7 | github_username: elm-community
8 |
9 | # Build settings
10 | markdown: kramdown
11 |
12 | # The following are supposed to be defaults per
13 | # https://help.github.com/articles/using-jekyll-with-pages/ but as of 2016-02-02
14 | # I have to set them explicitly for correct output.
15 | kramdown:
16 | input: GFM
17 | hard_wrap: false
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # elm-faq
2 | ## FAQ about the Elm language.
3 |
4 | Here are some [questions and answers](https://elm-community.github.io/elm-faq/) often seen on the #elm IRC channel on freenode,
5 | on the Elm Slack,
6 | and on the [elm-discuss](https://groups.google.com/forum/#!forum/elm-discuss) group.
7 |
8 | We welcome contributions as pull requests.
9 |
10 | ## How to serve a development version of the FAQ
11 |
12 | ### Setup
13 |
14 | ```bash
15 | sudo gem install bundler
16 | git clone git@github.com:elm-community/elm-faq.git
17 | cd elm-faq
18 | bundle install
19 | ```
20 |
21 | ### Serving
22 |
23 | ```bash
24 | cd elm-faq
25 | bundle exec jekyll serve
26 | ```
27 |
--------------------------------------------------------------------------------
/_includes/head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/css/main.scss:
--------------------------------------------------------------------------------
1 | ---
2 | # Only the main Sass file needs front matter (the dashes are enough)
3 | ---
4 | @charset "utf-8";
5 |
6 |
7 |
8 | // Our variables
9 | $base-font-family: Helvetica, Arial, sans-serif;
10 | $base-font-size: 16px;
11 | $small-font-size: $base-font-size * 0.875;
12 | $base-line-height: 1.5;
13 |
14 | $spacing-unit: 30px;
15 |
16 | $text-color: #111;
17 | $background-color: #fdfdfd;
18 | $brand-color: #2a7ae2;
19 |
20 | $grey-color: #828282;
21 | $grey-color-light: lighten($grey-color, 40%);
22 | $grey-color-dark: darken($grey-color, 25%);
23 |
24 | $on-palm: 600px;
25 | $on-laptop: 800px;
26 |
27 |
28 |
29 | // Using media queries with like this:
30 | // @include media-query($palm) {
31 | // .wrapper {
32 | // padding-right: $spacing-unit / 2;
33 | // padding-left: $spacing-unit / 2;
34 | // }
35 | // }
36 | @mixin media-query($device) {
37 | @media screen and (max-width: $device) {
38 | @content;
39 | }
40 | }
41 |
42 |
43 |
44 | // Import partials from `sass_dir` (defaults to `_sass`)
45 | @import
46 | "base",
47 | "layout",
48 | "syntax-highlighting"
49 | , "custom"
50 | ;
51 |
--------------------------------------------------------------------------------
/17-tasks.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Elm 0.17 Tasks
3 | layout: page
4 | ---
5 |
6 | Here are some ways to convert Elm 0.16 code that uses `Effects.task` into Elm 0.17.
7 |
8 | The cases are sorted by priority, so use the first one that applies to your code.
9 |
10 |
11 |
12 |
Elm 0.16 example
13 |
Elm 0.17 equivalent
14 |
15 |
16 |
task |> Task.toMaybe |> Effects.task
17 |
task |> Task.perform (always Nothing) Just
18 |
19 |
20 |
task |> Task.toResult |> Effects.task
21 |
task |> Task.perform Err Ok
22 |
23 |
24 |
task |> Task.map action |> Effects.task
25 |
task |> Task.Extra.performFailproof action
26 |
27 |
28 |
task |> Effects.task
29 |
task |> Task.Extra.performFailproof identity
30 |
31 |
32 |
33 |
34 | The function `performFailproof` used in two places above is from package [NoRedInk/elm-task-extra](http://package.elm-lang.org/packages/NoRedInk/elm-task-extra).
35 |
36 | This recommendation comes from an
37 | [elm-discuss posting](https://groups.google.com/d/msg/elm-discuss/gkdCrioDsUQ/cJn5-n6fFQAJ)
38 | by Janis Voigtländer on 2016-05-19.
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/_includes/header.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/assets/filter.js:
--------------------------------------------------------------------------------
1 | var container = document.getElementById('elm-content');
2 |
3 | // Collect information about the implicit sections of the document. Each section
4 | // starts with an H3 element and continues until the next heading of equal or
5 | // higher value.
6 |
7 | var h3s = document.getElementsByTagName("H3");
8 | var h3sArr = [].slice.call(h3s); // convert to array to allow map()
9 |
10 | var h3sInfo = h3sArr.map( function(elmt, index) {
11 | var title = elmt.innerText || elmt.textContent;
12 |
13 | var content = "";
14 | for (var next = elmt.nextSibling; next; next = next.nextSibling) {
15 | if (next.tagName == "H3" || next.tagName == "H2" || next.tagName == "H1") {
16 | break;
17 | }
18 | content += next.textContent;
19 | }
20 |
21 | return { id: elmt.id, title: title, content: content };
22 | });
23 |
24 |
25 | Elm.Filter.embed(container, h3sInfo);
26 |
27 | // When following a link to the comprising page with a hash (HTML anchor
28 | // name) the browser often scrolls to the wrong offset in the document, as
29 | // if the content inserted by the Filter app above was not accounted
30 | // for. The following kluge works around that.
31 |
32 | if (window.location.hash) {
33 | var save = window.location.hash;
34 | window.location.hash = "";
35 | setTimeout(function() {
36 | window.location.hash = save;
37 | }, 0);
38 | }
39 |
--------------------------------------------------------------------------------
/operators.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | ---
4 |
67 | The above lists the core infix operators in descending order of precedence.
68 |
69 |
70 | Function application (by adjacency) is higher priority than all operators and
71 | is left-associative: f g h x is interpreted as ((f g) h) x.
72 |
73 |
74 | *
75 | The comparison operators (precedence 4) are non-associative.
76 |
83 |
84 |
--------------------------------------------------------------------------------
/16.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Elm 0.16
3 | layout: page
4 | ---
5 |
6 | **Warning: This page concerns Elm version 0.16.**
7 | The information here is no longer correct for the current version of Elm.
8 |
9 | For general questions about the current version see the [main FAQ page](index.html).
10 |
11 | #### Contents
12 |
13 |
14 |
15 |
16 | ### Why does elm-repl (or elm-make) report "cannot find module 'Html'"?
17 | You need to install the Html module:
18 |
19 | elm package install evancz/elm-html
20 |
21 | Several modules are [available by default](http://package.elm-lang.org/packages/elm-lang/core/latest) in the base Elm tools but other common modules like Html have to be installed in the working directory before they can be used in elm-make, elm-repl, and elm-reactor.
22 |
23 |
24 | ### How do I generate an Action as an Effect?
25 |
26 | Effects.task (Task.succeed SomeAction)
27 |
28 |
29 | ### Why isn't my StartApp-based program running any tasks?
30 |
31 | You need to set `app.port`.
32 |
33 | ```haskell
34 | port tasks : Signal (Task.Task Never ())
35 | port tasks =
36 | app.tasks
37 | ```
38 |
39 |
40 | ### Why doesn't the `<~` operator work?
41 |
42 | It was removed in Elm version 0.16. You can still get it (or the equivalent `andMap`) from
43 | [Signal.Extra](http://package.elm-lang.org/packages/Apanatshka/elm-signal-extra/latest/Signal-Extra)
44 | instead.
45 |
46 |
47 | ### Why doesn't my application get the initial value of Window.dimensions?
48 |
49 | For example, given this:
50 |
51 | ```haskell
52 | modelInit = { window = (-1,-1) }
53 |
54 | main = Signal.map Element.show model
55 |
56 | model = Signal.foldp (\d s -> {s | window = d}) modelInit Window.dimensions
57 | ```
58 |
59 | the displayed value will remain at "{ window = (-1,-1) }" until the window is resized, at which time the display tracks all changes.
60 |
61 | This arises because `Signal.foldp` does not use the initial value of its input signal (`Window.dimensions` in this case).
62 |
63 | One solution is to use the `foldp'` function from the Apanatshka/elm-signal-extra package, as follows:
64 |
65 | ```haskell
66 | model = Signal.Extra.foldp' (\d s -> {s | window = d}) (\d -> { window = d }) Window.dimensions
67 | ```
68 |
69 | Whereas `foldp` takes an initial value parameter, `foldp'` takes instead a function from the initial value of the input signal to the initial value returned by `foldp'`.
70 |
71 | Since StartApp uses `foldp` this problem with initial values can arise when it is used. Also, the problem is not specific to Window.dimensions; it can arise for any input signal whose initial value is of interest.
72 |
73 |
74 |
75 | ### Why is my app failing immediately saying "Cannot read property 'make' of undefined"?
76 |
77 | That can happen if you write custom Javascript code to call `Elm.embed()` or `Elm.fullscreen()` and the application name used there (the first parameter) does not match the main module name.
78 |
79 | For example, if Foo.elm contains the `main` function for your app then your Javascript code should call it like this:
80 |
81 | ```javascript
82 | app = Elm.embed(Elm.Foo, ...)
83 | ```
84 |
85 | If you use a name other than `Elm.Foo` there you will likely get that "Cannot read property" error.
86 |
--------------------------------------------------------------------------------
/_sass/_syntax-highlighting.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Syntax highlighting styles
3 | */
4 | .highlight {
5 | ////background: #fff;
6 | @extend %vertical-rhythm;
7 |
8 | .c { color: #998; font-style: italic } // Comment
9 | .err { color: #a61717; background-color: #e3d2d2 } // Error
10 | .k { font-weight: bold } // Keyword
11 | .o { font-weight: bold } // Operator
12 | .cm { color: #998; font-style: italic } // Comment.Multiline
13 | .cp { color: #999; font-weight: bold } // Comment.Preproc
14 | .c1 { color: #998; font-style: italic } // Comment.Single
15 | .cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special
16 | .gd { color: #000; background-color: #fdd } // Generic.Deleted
17 | .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific
18 | .ge { font-style: italic } // Generic.Emph
19 | .gr { color: #a00 } // Generic.Error
20 | .gh { color: #999 } // Generic.Heading
21 | .gi { color: #000; background-color: #dfd } // Generic.Inserted
22 | .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific
23 | .go { color: #888 } // Generic.Output
24 | .gp { color: #555 } // Generic.Prompt
25 | .gs { font-weight: bold } // Generic.Strong
26 | .gu { color: #aaa } // Generic.Subheading
27 | .gt { color: #a00 } // Generic.Traceback
28 | .kc { font-weight: bold } // Keyword.Constant
29 | .kd { font-weight: bold } // Keyword.Declaration
30 | .kp { font-weight: bold } // Keyword.Pseudo
31 | .kr { font-weight: bold } // Keyword.Reserved
32 | .kt { color: #458; font-weight: bold } // Keyword.Type
33 | .m { color: #099 } // Literal.Number
34 | .s { color: #d14 } // Literal.String
35 | .na { color: #008080 } // Name.Attribute
36 | .nb { color: #0086B3 } // Name.Builtin
37 | .nc { color: #458; font-weight: bold } // Name.Class
38 | .no { color: #008080 } // Name.Constant
39 | .ni { color: #800080 } // Name.Entity
40 | .ne { color: #900; font-weight: bold } // Name.Exception
41 | .nf { color: #900; font-weight: bold } // Name.Function
42 | .nn { color: #555 } // Name.Namespace
43 | .nt { color: #000080 } // Name.Tag
44 | .nv { color: #008080 } // Name.Variable
45 | .ow { font-weight: bold } // Operator.Word
46 | .w { color: #bbb } // Text.Whitespace
47 | .mf { color: #099 } // Literal.Number.Float
48 | .mh { color: #099 } // Literal.Number.Hex
49 | .mi { color: #099 } // Literal.Number.Integer
50 | .mo { color: #099 } // Literal.Number.Oct
51 | .sb { color: #d14 } // Literal.String.Backtick
52 | .sc { color: #d14 } // Literal.String.Char
53 | .sd { color: #d14 } // Literal.String.Doc
54 | .s2 { color: #d14 } // Literal.String.Double
55 | .se { color: #d14 } // Literal.String.Escape
56 | .sh { color: #d14 } // Literal.String.Heredoc
57 | .si { color: #d14 } // Literal.String.Interpol
58 | .sx { color: #d14 } // Literal.String.Other
59 | .sr { color: #009926 } // Literal.String.Regex
60 | .s1 { color: #d14 } // Literal.String.Single
61 | .ss { color: #990073 } // Literal.String.Symbol
62 | .bp { color: #999 } // Name.Builtin.Pseudo
63 | .vc { color: #008080 } // Name.Variable.Class
64 | .vg { color: #008080 } // Name.Variable.Global
65 | .vi { color: #008080 } // Name.Variable.Instance
66 | .il { color: #099 } // Literal.Number.Integer.Long
67 | }
68 |
--------------------------------------------------------------------------------
/_includes/footer.html:
--------------------------------------------------------------------------------
1 |
63 |
--------------------------------------------------------------------------------
/_sass/_base.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Reset some basic elements
3 | */
4 | body, h1, h2, h3, h4, h5, h6,
5 | p, blockquote, pre, hr,
6 | dl, dd, ol, ul, figure {
7 | margin: 0;
8 | padding: 0;
9 | }
10 |
11 |
12 |
13 | /**
14 | * Basic styling
15 | */
16 | body {
17 | font-family: $base-font-family;
18 | font-size: $base-font-size;
19 | line-height: $base-line-height;
20 | font-weight: 300;
21 | color: $text-color;
22 | background-color: $background-color;
23 | -webkit-text-size-adjust: 100%;
24 | }
25 |
26 |
27 |
28 | /**
29 | * Set `margin-bottom` to maintain vertical rhythm
30 | */
31 | h1, h2, h3, h4, h5, h6,
32 | p, blockquote, pre,
33 | ul, ol, dl, figure,
34 | %vertical-rhythm {
35 | margin-bottom: $spacing-unit / 2;
36 | }
37 |
38 |
39 |
40 | /**
41 | * Images
42 | */
43 | img {
44 | max-width: 100%;
45 | vertical-align: middle;
46 | }
47 |
48 |
49 |
50 | /**
51 | * Figures
52 | */
53 | figure > img {
54 | display: block;
55 | }
56 |
57 | figcaption {
58 | font-size: $small-font-size;
59 | }
60 |
61 |
62 |
63 | /**
64 | * Lists
65 | */
66 | ul, ol {
67 | margin-left: $spacing-unit;
68 | }
69 |
70 | li {
71 | > ul,
72 | > ol {
73 | margin-bottom: 0;
74 | }
75 | }
76 |
77 |
78 |
79 | /**
80 | * Headings
81 | */
82 | h1, h2, h3, h4, h5, h6 {
83 | font-weight: 300;
84 | }
85 |
86 |
87 |
88 | /**
89 | * Links
90 | */
91 | a {
92 | color: $brand-color;
93 | text-decoration: none;
94 |
95 | &:visited {
96 | color: darken($brand-color, 15%);
97 | }
98 |
99 | &:hover {
100 | color: $text-color;
101 | text-decoration: underline;
102 | }
103 | }
104 |
105 |
106 |
107 | /**
108 | * Blockquotes
109 | */
110 | blockquote {
111 | color: $grey-color;
112 | border-left: 4px solid $grey-color-light;
113 | padding-left: $spacing-unit / 2;
114 | font-size: 18px;
115 | letter-spacing: -1px;
116 | font-style: italic;
117 |
118 | > :last-child {
119 | margin-bottom: 0;
120 | }
121 | }
122 |
123 |
124 |
125 | /**
126 | * Code formatting
127 | */
128 | pre,
129 | code {
130 | font-size: 15px;
131 | /* border: 1px solid $grey-color-light; */
132 | border-radius: 3px;
133 | background-color: rgb(247, 247, 247);
134 | }
135 |
136 | code {
137 | padding: 1px 5px;
138 | }
139 |
140 | pre {
141 | padding: 8px 12px;
142 | overflow: auto;
143 |
144 | > code {
145 | border: 0;
146 | padding-right: 0;
147 | padding-left: 0;
148 | }
149 | }
150 |
151 |
152 |
153 | /**
154 | * Wrapper
155 | */
156 | .wrapper {
157 | max-width: -webkit-calc(800px - (#{$spacing-unit} * 2));
158 | max-width: calc(800px - (#{$spacing-unit} * 2));
159 | margin-right: auto;
160 | margin-left: auto;
161 | padding-right: $spacing-unit;
162 | padding-left: $spacing-unit;
163 | @extend %clearfix;
164 |
165 | @include media-query($on-laptop) {
166 | max-width: -webkit-calc(800px - (#{$spacing-unit}));
167 | max-width: calc(800px - (#{$spacing-unit}));
168 | padding-right: $spacing-unit / 2;
169 | padding-left: $spacing-unit / 2;
170 | }
171 | }
172 |
173 |
174 |
175 | /**
176 | * Clearfix
177 | */
178 | %clearfix {
179 |
180 | &:after {
181 | content: "";
182 | display: table;
183 | clear: both;
184 | }
185 | }
186 |
187 |
188 |
189 | /**
190 | * Icons
191 | */
192 | .icon {
193 |
194 | > svg {
195 | display: inline-block;
196 | width: 16px;
197 | height: 16px;
198 | vertical-align: middle;
199 |
200 | path {
201 | fill: $grey-color;
202 | }
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/17.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Elm 0.17
3 | layout: page
4 | ---
5 | This page concerns questions that arose with Elm version 0.17.
6 |
7 | For general questions see the [main FAQ page](index.html).
8 |
9 | #### Contents
10 |
11 |
12 |
13 |
14 | ### Where are the official documents about Elm version 0.17?
15 |
16 | * [A Farewell to FRP][farewell]: Evan's blog announcement of Elm 0.17.
17 | * [Upgrading to 0.17][upgrade guide]: The official upgrade guide.
18 | * [Introduction to Elm][guide]: The official guide to the Elm 0.17 language and core packages.
19 |
20 | Others have written about the conversion as well:
21 |
22 | * [Migrating signal usage from Elm 0.16 to 0.17](http://noredink.github.io/posts/signalsmigration.html)
23 |
24 | ### Why does elm-make complain "Cannot find module 'Basics'"?
25 |
26 | You need to install the elm-lang/core package.
27 |
28 | This often arises when upgrading a package from 0.16 after removing all dependencies from elm-package.json.
29 |
30 | ### Where is the evancz/elm-html package?
31 |
32 | It's now at elm-lang/html. See the [upgrade guide] about this and other core packages that moved.
33 |
34 | [farewell]: http://elm-lang.org/blog/farewell-to-frp
35 | [upgrade guide]: https://github.com/elm-lang/elm-platform/blob/master/upgrade-docs/0.17.md
36 | [guide]: http://guide.elm-lang.org/
37 |
38 | ### Where is `Effects.task`?
39 |
40 | It's gone. `Task.perform` is used instead.
41 |
42 | See some examples of [how to convert to Task.perform](17-tasks.html).
43 |
44 | ### Why am I getting "TypeError: Elm.embed is not a function"?
45 |
46 | The JavaScript code for calling the Elm entry point must now look like this:
47 |
48 | ```javascript
49 | Elm.MyApp.embed(someElement);
50 | ```
51 |
52 | It used to look like `Elm.embed(Elm.MyApp, someElement)`.
53 |
54 | It's similar for the `fullscreen` and `worker` functions.
55 |
56 | ### What happened to all the core modules?
57 |
58 | Many core modules have been moved out into separate packages, usually under `elm-lang`.
59 |
60 | * `Graphics` is now in `evancz/elm-graphics`
61 | * `Trampoline` is now in `elm-lang/trampoline` and has some renames
62 | * `Trampoline.trampoline` is now `Trampoline.evaluate`
63 | * `Trampoline.Done` is now `Trampoline.done` (function instead of constructor)
64 | * `Trampoline.Continue` is now `Trampoline.jump` (function instead of constructor)
65 | * `Mouse` is now in `elm-lang/mouse`
66 | * `Window` is now in `elm-lang/window`
67 | * `Keyboard` is now in `elm-lang/keyboard`
68 |
69 | Also:
70 |
71 | * `maxsnew/lazy` is now `elm-lang/lazy`
72 |
73 | ### What is now in elm-community?
74 |
75 | * `NoRedInk/elm-lazy-list` is now `elm-community/elm-lazy-list`
76 | * `NoRedInk/elm-random-extra` is now `elm-community/random-extra`
77 | * `Random.Bool` has been removed as it is now in `elm-lang/core`'s `Random`
78 | * `Random.Function` has been removed entirely
79 | * `deadfoxygrandpa/elm-test` is now `elm-community/elm-test`
80 | * It no longer depends on `laszlopandy/elm-console`. To run tests in node use: `ElmTest.runSuite`
81 | * `elementRunner` is gone, use `runSuiteHtml` instead
82 |
83 | ### Why am I getting "cannot find module" errors while upgrading a project from 0.16?
84 |
85 | Cached or obsolete/renamed package versions may be getting in the way. To get a clean start, try these (from simplest to most drastic):
86 |
87 | 1. Remove all of elm-stuff.
88 | 2. Remove all the package names from the `dependencies` section of elm-package.json and install packages again as needed. You may have to explicitly install elm-lang/core again.
89 | 3. Remove all of ~/.elm (on linux or Mac OSX) or ~/AppData/Roaming/elm/package (on Windows).
90 |
91 | ### Does hot-reloading work in elm-reactor now?
92 |
93 | Not yet. Work is well underway to improve elm-reactor.
94 |
95 | ### Why does the compiler complain about "I am looking for one of the following things: whitespace" near the beginning of the file?
96 |
97 | The `exposing` clause is now required at the beginning of each module.
98 | For example, you now need `module Foo exposing (..)` where prior to Elm 0.17 you could use `module Foo where`.
99 |
100 |
101 | ### Are static ports still available?
102 |
103 | No. In Elm 0.17 you'll have to pass any static data from JS to Elm via the "flags" argument to the `embed()`, `fullscreen()`, or `worker()` functions.
104 |
105 | ### Why does elm-make report "I cannot find module 'Graphics.Collage'" even though evancz/elm-graphics is installed?
106 |
107 | You now need to do `import Collage` to get that module. It's no longer namespaced under `Graphics`.
108 |
109 |
110 | ## Footnotes
111 |
--------------------------------------------------------------------------------
/assets/anchor.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * AnchorJS - v3.2.2 - 2016-10-05
3 | * https://github.com/bryanbraun/anchorjs
4 | * Copyright (c) 2016 Bryan Braun; Licensed MIT
5 | */
6 | !function(A,e){"use strict";"function"==typeof define&&define.amd?define([],e):"object"==typeof module&&module.exports?module.exports=e():(A.AnchorJS=e(),A.anchors=new A.AnchorJS)}(this,function(){"use strict";function A(A){function e(A){A.icon=A.hasOwnProperty("icon")?A.icon:"",A.visible=A.hasOwnProperty("visible")?A.visible:"hover",A.placement=A.hasOwnProperty("placement")?A.placement:"right",A.class=A.hasOwnProperty("class")?A.class:"",A.truncate=A.hasOwnProperty("truncate")?Math.floor(A.truncate):64}function t(A){var e;if("string"==typeof A||A instanceof String)e=[].slice.call(document.querySelectorAll(A));else{if(!(Array.isArray(A)||A instanceof NodeList))throw new Error("The selector provided to AnchorJS was invalid.");e=[].slice.call(A)}return e}function n(){if(null===document.head.querySelector("style.anchorjs")){var A,e=document.createElement("style"),t=" .anchorjs-link { opacity: 0; text-decoration: none; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }",n=" *:hover > .anchorjs-link, .anchorjs-link:focus { opacity: 1; }",i=' @font-face { font-family: "anchorjs-icons"; src: url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype"); }',o=" [data-anchorjs-icon]::after { content: attr(data-anchorjs-icon); }";e.className="anchorjs",e.appendChild(document.createTextNode("")),A=document.head.querySelector('[rel="stylesheet"], style'),void 0===A?document.head.appendChild(e):document.head.insertBefore(e,A),e.sheet.insertRule(t,e.sheet.cssRules.length),e.sheet.insertRule(n,e.sheet.cssRules.length),e.sheet.insertRule(o,e.sheet.cssRules.length),e.sheet.insertRule(i,e.sheet.cssRules.length)}}this.options=A||{},this.elements=[],e(this.options),this.isTouchDevice=function(){return!!("ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch)},this.add=function(A){var i,o,s,c,r,a,h,l,u,d,f,p,w=[];if(e(this.options),p=this.options.visible,"touch"===p&&(p=this.isTouchDevice()?"always":"hover"),A||(A="h1, h2, h3, h4, h5, h6"),i=t(A),0===i.length)return!1;for(n(),o=document.querySelectorAll("[id]"),s=[].map.call(o,function(A){return A.id}),r=0;r-1,t=A.lastChild&&(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ")>-1;return e||t||!1}}return A});
7 |
--------------------------------------------------------------------------------
/_sass/_layout.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Site header
3 | */
4 | .site-header {
5 | border-top: 5px solid $grey-color-dark;
6 | border-bottom: 1px solid $grey-color-light;
7 | min-height: 56px;
8 |
9 | // Positioning context for the mobile navigation icon
10 | position: relative;
11 | }
12 |
13 | .site-title {
14 | font-size: 26px;
15 | line-height: 56px;
16 | letter-spacing: -1px;
17 | margin-bottom: 0;
18 | float: left;
19 |
20 | &,
21 | &:visited {
22 | color: $grey-color-dark;
23 | }
24 | }
25 |
26 | .site-nav {
27 | float: right;
28 | line-height: 56px;
29 |
30 | .menu-icon {
31 | display: none;
32 | }
33 |
34 | .page-link {
35 | color: $text-color;
36 | line-height: $base-line-height;
37 |
38 | // Gaps between nav items, but not on the first one
39 | &:not(:first-child) {
40 | margin-left: 20px;
41 | }
42 | }
43 |
44 | @include media-query($on-palm) {
45 | position: absolute;
46 | top: 9px;
47 | right: 30px;
48 | background-color: $background-color;
49 | border: 1px solid $grey-color-light;
50 | border-radius: 5px;
51 | text-align: right;
52 |
53 | .menu-icon {
54 | display: block;
55 | float: right;
56 | width: 36px;
57 | height: 26px;
58 | line-height: 0;
59 | padding-top: 10px;
60 | text-align: center;
61 |
62 | > svg {
63 | width: 18px;
64 | height: 15px;
65 |
66 | path {
67 | fill: $grey-color-dark;
68 | }
69 | }
70 | }
71 |
72 | .trigger {
73 | clear: both;
74 | display: none;
75 | }
76 |
77 | &:hover .trigger {
78 | display: block;
79 | padding-bottom: 5px;
80 | }
81 |
82 | .page-link {
83 | display: block;
84 | padding: 5px 10px;
85 | }
86 | }
87 | }
88 |
89 | .logo {
90 | float: left;
91 | padding-right: 20px;
92 | img {
93 | height: 80px;
94 | }
95 | }
96 |
97 |
98 | /**
99 | * Site footer
100 | */
101 | .site-footer {
102 | border-top: 1px solid $grey-color-light;
103 | padding: $spacing-unit 0;
104 | }
105 |
106 | .footer-heading {
107 | font-size: 18px;
108 | margin-bottom: $spacing-unit / 2;
109 | }
110 |
111 | .contact-list,
112 | .social-media-list {
113 | list-style: none;
114 | margin-left: 0;
115 | }
116 |
117 | .footer-col-wrapper {
118 | font-size: 15px;
119 | color: $grey-color;
120 | margin-left: -$spacing-unit / 2;
121 | @extend %clearfix;
122 | }
123 |
124 | .footer-col {
125 | float: left;
126 | margin-bottom: $spacing-unit / 2;
127 | padding-left: $spacing-unit / 2;
128 | }
129 |
130 | .footer-col-1 {
131 | width: -webkit-calc(35% - (#{$spacing-unit} / 2));
132 | width: calc(35% - (#{$spacing-unit} / 2));
133 | }
134 |
135 | .footer-col-2 {
136 | width: -webkit-calc(20% - (#{$spacing-unit} / 2));
137 | width: calc(20% - (#{$spacing-unit} / 2));
138 | }
139 |
140 | .footer-col-3 {
141 | width: -webkit-calc(45% - (#{$spacing-unit} / 2));
142 | width: calc(45% - (#{$spacing-unit} / 2));
143 | }
144 |
145 | @include media-query($on-laptop) {
146 | .footer-col-1,
147 | .footer-col-2 {
148 | width: -webkit-calc(50% - (#{$spacing-unit} / 2));
149 | width: calc(50% - (#{$spacing-unit} / 2));
150 | }
151 |
152 | .footer-col-3 {
153 | width: -webkit-calc(100% - (#{$spacing-unit} / 2));
154 | width: calc(100% - (#{$spacing-unit} / 2));
155 | }
156 | }
157 |
158 | @include media-query($on-palm) {
159 | .footer-col {
160 | float: none;
161 | width: -webkit-calc(100% - (#{$spacing-unit} / 2));
162 | width: calc(100% - (#{$spacing-unit} / 2));
163 | }
164 | }
165 |
166 |
167 |
168 | /**
169 | * Page content
170 | */
171 | .page-content {
172 | padding: $spacing-unit 0;
173 | }
174 |
175 | .page-heading {
176 | font-size: 20px;
177 | }
178 |
179 | .post-list {
180 | margin-left: 0;
181 | list-style: none;
182 |
183 | > li {
184 | margin-bottom: $spacing-unit;
185 | }
186 | }
187 |
188 | .post-meta {
189 | font-size: $small-font-size;
190 | color: $grey-color;
191 | }
192 |
193 | .post-link {
194 | display: block;
195 | font-size: 24px;
196 | }
197 |
198 |
199 |
200 | /**
201 | * Posts
202 | */
203 | .post-header {
204 | margin-bottom: $spacing-unit;
205 | }
206 |
207 | .post-title {
208 | font-size: 42px;
209 | letter-spacing: -1px;
210 | line-height: 1;
211 |
212 | @include media-query($on-laptop) {
213 | font-size: 36px;
214 | }
215 | }
216 |
217 | .post-content {
218 | margin-bottom: $spacing-unit;
219 |
220 | h2 {
221 | font-size: 32px;
222 |
223 | @include media-query($on-laptop) {
224 | font-size: 28px;
225 | }
226 |
227 | margin-top: 2em;
228 |
229 | }
230 |
231 | h3 {
232 | font-size: 26px;
233 |
234 | @include media-query($on-laptop) {
235 | font-size: 22px;
236 | }
237 |
238 | margin-top: 2em;
239 |
240 | }
241 |
242 | h4 {
243 | font-size: 20px;
244 |
245 | @include media-query($on-laptop) {
246 | font-size: 18px;
247 | }
248 | }
249 | }
250 |
--------------------------------------------------------------------------------
/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Elm FAQ
3 | layout: page
4 | ---
5 |
6 | **This page is mostly for folks _learning_ Elm.** It aggregates questions that are commonly
7 | asked on [the Slack channel][slack], [the IRC channel][irc], or [Discourse][discourse].
8 | Those are all friendly and helpful places to go if you do not find the answer to your
9 | question here!
10 |
11 | [slack]: http://elmlang.herokuapp.com/
12 | [irc]: http://webchat.freenode.net/?channels=elm
13 | [discourse]: https://discourse.elm-lang.org/
14 |
15 | - Contributions to [this document](https://github.com/elm-community/elm-faq)
16 | are welcome!
17 |
18 | - This document is about the current version of Elm (0.19 / 0.19.1). See also the
19 | [Elm 0.17 FAQ](17.html) about upgrading to Elm 0.17. See the [Elm 0.16 FAQ](16.html)
20 | about that older version of Elm.
21 |
22 | #### Contents
23 |
24 |
25 |
26 | ### What is the difference between `type` and `type alias`?
27 |
28 | `type` defines and names a new type (which behaves like an enum with data
29 | attached), and `type alias` gives a name to an existing type.
30 |
31 | `type alias` isn't creating a distinct type, it is literally just giving a name to an existing type. A type alias will save you keystrokes, but do nothing more. [ref](https://groups.google.com/forum/#!topic/elm-discuss/YgRqI5s2S7Y)
32 |
33 | ### Why does elm repl (or elm make) report "cannot find module 'Html'"?
34 |
35 | You need to install the Html module:
36 |
37 | elm install elm/html
38 |
39 | Several modules are [available by default](https://package.elm-lang.org/packages/elm/core/latest/) in the base Elm tools but other common modules like Html have to be installed in the working directory before they can be used in `elm make`, `elm repl`, and `elm reactor`.
40 |
41 | ### How do I know what package name to use for `elm install`?
42 |
43 | Search on [package.elm-lang.org](https://package.elm-lang.org/) for the module name and use the package name that you find there.
44 |
45 | ### How can I write debugging information to the console?
46 |
47 | Wrap any value with `Debug.log “some message”` and that message and the value will be written to the javascript console every time the value is evaluated. For example:
48 |
49 | ```haskell
50 | case Debug.log "action" action of
51 | ```
52 |
53 | If you want to just log a message and value without using that value, try this in a `let` clause:
54 |
55 | ```haskell
56 | _ = Debug.log "my message" someValue
57 | ```
58 |
59 | Also see [`Debug.todo`](https://package.elm-lang.org/packages/elm/core/latest/Debug#todo)
60 | which gets special treatment from the compiler to provide additional information in the output.
61 |
62 | ### How do I install an older version of Elm, 0.16 for example?
63 |
64 | npm install -g elm@0.16
65 |
66 | If you need to switch between multiple versions of elm, consider [elmenv](https://github.com/sonnym/elmenv).
67 |
68 | ### What's the difference between `Html Msg` and `Html msg`?
69 |
70 | `msg` is a placeholder used when the HTML doesn't send any messages of type `Msg` (as in `type Msg = ...`). This is just as `a` is used as a placeholder in `List a` when the list is of any type, rather than of strings (`List String`) or integers (`List Int`) etc.. `msg` means "message of any type".
71 |
72 | ### How can I output literal HTML and avoid escaping of entities?
73 |
74 | We used to use the `innerHTML` property for this, but Elm 0.19 no longer allows that.
75 |
76 | See [issue #172](https://github.com/elm/html/issues/172) for discussion of the issue and possible solutions.
77 |
78 | ### What does `()` mean?
79 |
80 | It is the empty tuple or [unit type](https://en.wikipedia.org/wiki/Unit_type). It serves much like `void`, `null`, or `None` in other languages.
81 |
82 | ### What good is the `<|` operator if it is just function application?
83 |
84 | It has lower precedence than function application expressed by adjacency (e.g. `sqrt x`) and is right-associative, and so it can be used instead of parentheses to group function arguments. For example, `a b ( c d )` is the same as `a b <| c d`, and `f ( g ( h x ) ) )` can be written as `f <| g <| h x`. More concretely, `max 3 (sqrt x)` can be written as `max 3 <| sqrt x`. [^application]
85 |
86 | [^application]: Function application and the `<|` operator are discussed at some length [here](https://groups.google.com/d/msg/elm-discuss/-PLj_eamKVQ/Zzo7iNx2FgAJ).
87 |
88 | Note: The `<|` operator is essentially the same as `$` in Haskell.
89 |
90 | ### What are the Elm operator precedences and associativities?
91 |
92 | See an [Elm operator precedence table](operators.html).
93 | See also [Basics.elm](https://github.com/elm/core/blob/master/src/Basics.elm).
94 |
95 | ### How can I use multiple Elm programs on the same page?
96 |
97 | You can compile multiple modules into a single elm.js and then instantiate whatever module you need on the appropriate div. [^multiplemodules] For example, bundle multiple main programs (without duplicating any code) into a single elm.js like this:
98 |
99 | elm make Header.elm Footer.elm Login.elm --output=elm.js
100 |
101 | and then use them like this:
102 |
103 | var header = Elm.Header.init({ node: document.getElementById('header') });
104 | var login = Elm.Footer.init({ node: document.getElementById('login') });
105 | var footer = Elm.Login.init({ node: document.getElementById('footer') });
106 |
107 | [^multiplemodules]:
108 |
109 | Use of multiple main modules in one application is discussed
110 | [here](https://groups.google.com/d/msg/elm-discuss/eEJgNnl99ps/keWXnn1KCwAJ)
111 | and [here](https://www.reddit.com/r/elm/comments/5vh1fi/where_do_you_suffer_most_while_programming_in_elm/deb93ay/).
112 |
113 | ### Does the main module file have to be named "Main.elm"?
114 |
115 | No, that is just a convention. Any module that binds `main` to a value of type `Program Never` can be an entry point to an Elm program.
116 |
117 | For example, if both Foo.elm and Bar.elm contain an appropriate binding of `main`,
118 | compiling via `elm make Foo.elm Bar.elm --output=elm.js` creates an elm.js file
119 | such that both `Elm.Foo.init({ node: someElement })` and
120 | `Elm.Bar.init({ node: someOtherElement })` can be used from the same HTML file.
121 |
122 | ### Why, when I import a module that defines a type, does the compiler know about the type name but not its constructors?
123 |
124 | You need to import the module in one of the following ways:
125 |
126 | import MyModule exposing (MyType(..)) -- import type and constructors
127 | import MyModule exposing (MyType) -- import only the type, but no constructors.
128 |
129 | Similarly, the module itself may export none, or all of a type's constructors.
130 |
131 | module MyModule exposing (MyType(..)) -- exposes all constructors
132 | module MyModule exposing (MyType) -- exposes only MyType, but no constructors.
133 |
134 | Just exposing `MyType` without the `(..)` will leave the constructors undefined. There are reasons for [keeping tags and record constructors secret](http://package.elm-lang.org/help/design-guidelines#keep-tags-and-record-constructors-secret).
135 |
136 | ### Where can I use type annotations?
137 |
138 | In addition to the top-level, type annotations can also be applied to `let` expressions.
139 |
140 | ```haskell
141 | let
142 | hypotenuse : Float -> Float -> Float
143 | hypotenuse a b =
144 | sqrt (a^2 + b^2)
145 | in
146 | hypotenuse 3 4
147 | ```
148 |
149 | ### How can I join the elmlang.slack.com community?
150 |
151 | Sign up at [elmlang.herokuapp.com](https://elmlang.herokuapp.com/).
152 |
153 | ### How can I recover when elm make fails with errors like "... openFile: does not exist"?
154 |
155 | That can happen when switching between elm versions. Try removing all of elm-stuff or just the build-artifacts:
156 |
157 | rm -r elm-stuff/build-artifacts
158 |
159 | ### How do I install an Elm package that has not been published to packages.elm-lang.org for use in my project?
160 |
161 | Clone the package into a separate directory and add its directory path to the `source-directories` section of the elm.json file for your project. As usual, you will also have to install any dependencies of the package.
162 |
163 | ### How can I parse Json into Elm data?
164 |
165 | Currently you have to write the [parsing
166 | code](https://package.elm-lang.org/packages/elm/json/latest/Json-Decode).
167 | Other than for [data passed over ports](https://guide.elm-lang.org/interop/ports.html) there is no automatic conversion (and even
168 | there, experts recommend writing the parser manually to be able to handle error
169 | cases).
170 |
171 | ### How can I pass a record/object over ports?
172 |
173 | You have to declare the type of each of its values.
174 |
175 | ```elm
176 | port outgoing : { floatValue : Float, stringValue : String } -> Cmd msg
177 |
178 | port incoming : ({ intValue : Int, stringValue : String } -> msg) -> Sub msg
179 | ```
180 |
181 | ### How can I report a compiler error message that could be better?
182 |
183 | Report the problem at the [error-message-catalog issue tracker](https://github.com/elm/error-message-catalog/issues)
184 | with a [short, self-contained, correct, example](http://sscce.org/) showing both the program and the problematic error messages.
185 |
186 | ### Does Elm have HashMaps?
187 |
188 | The core [Dict](https://package.elm-lang.org/packages/elm/core/latest/Dict) package provides a dictionary mapping unique keys to values. There are some restrictions on key value types; in particular, records cannot be keys.
189 |
190 | ### Why does my app fail immediately with a console error of "Uncaught TypeError: Cannot read property 'appendChild' of null"?
191 |
192 | Make sure that you are calling Elm's javascript `embed` function _after_ the
193 | referenced container has been defined in the HTML file.
194 |
195 | Similarly, Elm's `fullscreen` function should be called only after the page body has started.
196 |
197 | Good practice is to call `embed` or `fullscreen` at the end of the document body.
198 |
199 | ### How can I load CSS (or other resources) in elm reactor?
200 |
201 | It's not easy. Elm reactor can serve CSS files and so you can write a custom
202 | HTML file that links in your CSS and the elm.js generated by Elm and then load
203 | that HTML file in elm reactor. But you have to generate the elm.js outside of
204 | elm reactor; it is not automatically built or rebuilt on changes to the Elm source.
205 |
206 | When you click an Elm source file in elm reactor it compiles just that file (and
207 | any dependencies) and sends back the generated javascript which then runs and
208 | displays the full page view of the program. So to add any CSS you have to do it
209 | in the Elm program itself. Here is an example (thanks to @pdamoc):
210 |
211 | ```elm
212 | import Html exposing (..)
213 | import Html.Attributes exposing (..)
214 |
215 | withStyle html =
216 | div []
217 | [ node "style" [type_ "text/css"]
218 | [text "@import url(https://cdnjs.cloudflare.com/ajax/libs/bulma/0.1.2/css/bulma.min.css)"]
219 | , html
220 | ]
221 |
222 | main =
223 | div []
224 | [ a [class "button is-primary"] [text "Primary"]
225 | , a [class "button is-info"] [text "Info"]
226 | ]
227 | |> withStyle
228 |
229 | ```
230 |
231 | For a more comprehensive solution, see the next question.
232 |
233 | ### How can I integrate Elm development into a larger app with CSS files and other resources?
234 |
235 | Elm-reactor is _not_ appropriate for that; it's geared toward simple pure-Elm applications.
236 |
237 | Consider using other hot-reload tools:
238 | [elm-live](https://github.com/tomekwi/elm-live),
239 | [elm-hot-loader](https://github.com/fluxxu/elm-hot-loader),
240 | [elm-webpack-starter](https://github.com/moarwick/elm-webpack-starter),
241 | [gulp-elm](https://github.com/philopon/gulp-elm/tree/master/example), or
242 | [devd](https://github.com/cortesi/devd).
243 |
244 | ### How does one render an HTML node conditionally?
245 |
246 | Use `Html.text ""` as an empty element. E.g.
247 |
248 | ```haskell
249 | if someCondition then
250 | Html.div [] [ {- ... some substantial Html value here ... -} ]
251 | else
252 | Html.text ""
253 | ```
254 |
255 | ### Does Elm have ad-hoc polymorphism or typeclasses?
256 |
257 | No. Elm provides three super-types that work like typeclasses:
258 | `number`, `comparable`, and `appendable`. [^compappend]
259 | The Elm language does not allow for defining our own super-types.
260 |
261 | [^compappend]: There is also `compappend` in the compiler but it does not appear to be exposed for use.
262 |
263 | The `number` type comprises `Int` and `Float`.
264 |
265 | The `comparable` type comprises `Int`, `Float`, `Char`, `String`, `List`, and tuples[^tuple_compare].
266 |
267 | [^tuple_compare]: Tuple comparison is supported only for tuples with 6 or fewer entries.
268 |
269 | The `appendable` type comprises `String`, `List`, and `text`[^text_append].
270 |
271 | [^text_append]: The compiler error messages refer to `text` being appendable; not sure what `text` means though. [FCY]
272 |
273 | When declaring types the names `number`, `comparable` and `appendable` serve as prefixes. For example, a function declared as
274 |
275 | ```haskell
276 | f : number -> number -> String
277 | ```
278 |
279 | means that `f` can take two `Int` values and return a `String`, or two `Float` values and return a `String`. It cannot take a combination of `Int` and `Float` though; the actual types have to be consistent.
280 |
281 | However, if declared as
282 |
283 | ```haskell
284 | f : number1 -> number2 -> String
285 | ```
286 |
287 | then it can also take an `Int` and a `Float` and return a `String`, or take a `Float` and an `Int` and return a `String`. The prefix gives the super-type that constrains the corresponding particular argument. The full super-type name, special prefix plus arbitrary (optional) suffix, determines whether the actual types have to be consistent.
288 |
289 | #### Why doesn't Elm have user-defined typeclasses?
290 |
291 | So far there have not been enough compelling cases to justify adding user-defined typeclasses to the language.
292 | See [compiler issue #1039](https://github.com/elm/compiler/issues/1039).
293 |
294 | ### Which special type variables are there, and how do they work?
295 |
296 | There are four special type vairables, which are `number`, `comparable`, `appendable`, and `compappend`. Please see question [Does Elm have ad-hoc polymorphism or typeclasses?](#does-elm-have-ad-hoc-polymorphism-or-typeclasses) for the details.
297 |
298 | These built-in type variables work differently from the ones defined by user defined. The main difference is these built-in type variables can only mean what they are defined to mean. For example:
299 |
300 | ```haskell
301 | type alias PlusFn t =
302 | { fn: t -> t -> t
303 | }
304 | ```
305 |
306 | It defines a type alias `PlusFn` which has one field `fn` which is a function that accepts two parameters which are of type `t`, and return a value of the same type. So, we can define any function which take two arguments and return one value, as long as they are of the same type, as the value of the `fn` field.
307 |
308 | ```haskell
309 | > PlusFn (\x y -> x + y)
310 | { fn = } : Repl.PlusFn number
311 | > PlusFn (\x y -> x ++ y)
312 | { fn = } : Repl.PlusFn appendable
313 | ```
314 |
315 | However, if we change the name `t` to any built-in type variable, it will work differently. Let's say we change `t` to `number`, then `fn` must operate on `number`, i.e. either `Int` or `Float`. Since `Int` and `Float` don't support `(++)` operation, so the following code will not be valid any more:
316 |
317 | ```haskell
318 | > PlusFn (\x y -> x ++ y)
319 | -- TYPE MISMATCH --------------------------------------------- repl-temp-000.elm
320 |
321 | The argument to function `PlusFn` is causing a mismatch.
322 |
323 | 4| PlusFn (\x y -> x ++ y)
324 | ^^^^^^^^^^^^^^
325 | Function `PlusFn` is expecting the argument to be:
326 |
327 | number -> number -> number
328 |
329 | But it is:
330 |
331 | appendable -> appendable -> appendable
332 | ```
333 |
334 | ### How can I change the value of a field in a record?
335 |
336 | Strictly speaking, you can't. Record values (like all Elm values) are
337 | immutable. However, you can _copy_ a record value and change one or
338 | more of its field values while doing so. Here is an example in
339 | elm repl:
340 |
341 | ```haskell
342 | > x = { name = "Chris", age = 30 }
343 | { name = "Chris", age = 30 } : { name : String, age : number }
344 | > y = { x | age = x.age + 1 }
345 | { name = "Chris", age = 31 } : { name : String, age : number }
346 | > y
347 | { name = "Chris", age = 31 } : { name : String, age : number }
348 | > x
349 | { name = "Chris", age = 30 } : { name : String, age : number }
350 | ```
351 |
352 | ### How can I change the value of a nested field?
353 |
354 | For example, given `model = { foo = { bar = 1 } }`, how does one update the value of the `bar` field?
355 | The expression `{ model | foo.bar = 2 }` will not compile.
356 |
357 | Here is an expression that returns a copy of `model` with `model.foo.bar` updated:
358 |
359 | `let foo = model.foo in { model | foo = { foo | bar = 2 } }`
360 |
361 | Or, perhaps more clearly, like this:
362 |
363 | `let fooBefore = model.foo in { model | foo = { fooBefore | bar = 2 } }`
364 |
365 | If you need to do this in more than one place, another way is to use a helper function:
366 |
367 | ```haskell
368 | { model | foo = updateHelp model.foo 2 }
369 |
370 | updateHelp foo int =
371 | { foo | bar = int }
372 | ```
373 |
374 | ### How can I pattern match a record and its values at the same time?
375 |
376 | You can use a special notation in function definition to pattern match a record and its values at the same time:
377 |
378 | ```haskell
379 | changeFooBar ({foo} as model) =
380 | { model | foo = { foo | bar = 2 } }
381 | ```
382 |
383 | See this [post](https://medium.com/elm-shorts/intro-to-records-in-elm-51bc5e933a57)
384 |
385 | ### Where are the `Cmd` and `Sub` types defined?
386 |
387 | They are defined in the core
388 | [Platform.Cmd](https://package.elm-lang.org/packages/elm/core/latest/Platform-Cmd)
389 | and
390 | [Platform.Sub](https://package.elm-lang.org/packages/elm/core/latest/Platform-Sub)
391 | modules.
392 |
393 | ### What is the difference between `Cmd Msg` and `Cmd msg`?
394 |
395 | `Cmd Msg` is a type of command where the resulting messages are of type `Msg`.
396 |
397 | `Cmd msg` is a more general type of command where the resulting message type is not known. It could just as well be written as `Cmd a` or `Cmd x`.
398 |
399 | ### Why does the compiler complain that "You are declaring port \`someName\` in a normal module."?
400 |
401 | Any module using ports must start with `port module` on the first line.
402 |
403 | ### How do I generate a new message as a command?
404 |
405 | The following function constructs a `Cmd` value from a message:
406 |
407 | ```haskell
408 | message : msg -> Cmd msg
409 | message msg =
410 | Task.perform identity (Task.succeed msg)
411 | ```
412 |
413 | However, this is often unnecessary. To handle a message produced by a call to `update` you may pass it straight back to `update` recursively. The package [ccapndave/elm-update-extra](http://package.elm-lang.org/packages/ccapndave/elm-update-extra/latest) provides helper functions for implementing this approach elegantly.
414 |
415 | The latter approach is likely to be more efficient in most cases. The former option may be attractive when recursive calls to `update` could cause an infinite loop, or for authors of reusable components interested in creating a clean encapsulation of their library's internal behavior.
416 |
417 | ### What is the difference between `Cmd` and `Task`?
418 |
419 | - `Cmd` is just a bag (i.e. multiset) of chunks of data. It is a functor, but it is not applicative or monadic. This means all you can do is apply a function to all the entries in the bag with `map` and add to the bag with `batch`.
420 |
421 | - `Task` is a way doing things in sequence. It is monadic, meaning it has an `andThen` in the API. This means you can say "Do X, and depending on the result, do Y or Z." From there you can keep chaining things.
422 |
423 | The point of this bag of commands is that you can gather all the things that need to happen from your whole app and get them done. The point of a task is to describe a particular thing you want to happen.[^cmd-vs-task]
424 |
425 | [^cmd-vs-task]: From Evan's #elm-dev Slack posting, 2016-05-16.
426 |
427 | If you need to do any kind of chaining stuff, use `Task`, and don't turn your task chain into a `Cmd` until you have no more chaining stuff to do.
428 | This is why APIs generally expose `Task` instances rather than `Cmd`: so you can do all the chaining you like, and you're in charge of finishing the job and turning whatever chain you've constructed into a `Cmd`.[^task-chaining]
429 |
430 | [^task-chaining]: From rtfeldman's #elm-dev Slack posting, 2016-05-16.
431 |
432 | ### How do I build an `onChange` handler for a `