├── How to Read a Type Annotation.md ├── Mailboxes, Messages, and Addresses.md ├── Modules, Exports, and Imports.md ├── README.md ├── Scope.md └── Where Did Null And Undefined Go.md /How to Read a Type Annotation.md: -------------------------------------------------------------------------------- 1 | # How to Read a Type Annotation 2 | 3 | If you come from a dynamically typed language like JavaScript or Ruby, or even a statically typed C-family language like 4 | Java, Elm's type annotations will look very strange. However, once you know how to read them, they make a lot more sense 5 | than `int strcmp(const char *s1, const char *s2);`. That's a good thing, because type annotations aren't for the 6 | compiler (it has type inference and can figure things out) but for you, the programmer. 7 | 8 | The most important reason to know about type annotations when you're starting out is that the docs for every function 9 | in the standard library have them. The annotation tells you how many arguments a function takes, what their types are, 10 | what order to pass them, and what the return type is. This information is not repeated elsewhere. 11 | 12 | Once you know how to read an annotation, it's fairly easy to write them. Doing so is is optional, but highly encouraged. 13 | Type annotations improve code by helping you think about what the function should be doing, and serve as 14 | compiler-verified documentation. (You know how an out-of-date comment is worse than no comment at all? Well, type 15 | annotations never get out of date.) In addition, if you ever want to publish a third-party library, you will need type 16 | annotations. 17 | 18 | ## Definitions 19 | 20 | The first thing to know is that `:` means "has type". 21 | 22 | ```elm 23 | answer : Int 24 | answer = 42 25 | ``` 26 | 27 | You can read "answer has type Int; answer equals forty-two". 28 | 29 | Common primitive types include `Int`, `Float`, `Bool`, and `String`. You can also pair up types into tuples, for example 30 | `(Int, Bool)`. This expands to arbitrarily many elements, i.e. `(Int, Float, Int)` is a 3-tuple with first element `Int`, 31 | second `Float`, third `Int`. 32 | 33 | ```elm 34 | myTuple : (String, Int, Bool) 35 | myTuple = ("the answer", 42, True) 36 | ``` 37 | 38 | In case you haven't noticed yet, types always begin with a capital letter (or open paren). 39 | 40 | There's one special type with only one value of that type. Both the type and value are read as "unit" and written as 41 | `()`. Unit is often used as a placeholder value, since if we know the type, we can anticipate the value. 42 | 43 | ## Functions 44 | 45 | `->` is used to separate the arguments and return value in the types of functions. It's pronounced "goes to". So for 46 | example, `String.length : String -> Int` is pronounced "string-dot-length has type String goes to Int". You just read 47 | left to right, like an English sentence. Oh and by the way, `String.length` means the `length` function in the `String` 48 | module. Whenever a capital letter is followed by a dot, it's a module, not a type. 49 | 50 | Things get interesting with multiple arrows, for example, `update : Action -> Model -> Model`. This function takes an 51 | Action and a Model as arguments (in that order), and returns a Model. Or, "update has type Action goes to Model goes to 52 | Model." 53 | 54 | What's really going on is that the type annotation is telling you about *partial application*: you can give a function 55 | only some of its arguments, and get a function as a result. You can always get the new function's type annotation by 56 | covering up part of the left side of the original function's annotation. 57 | 58 | ```elm 59 | example : Model -> Model 60 | example = update someAction 61 | ``` 62 | 63 | There are implied parentheses in the annotation, so we could also write: `update : Action -> (Model -> Model)`. 64 | 65 | You probably don't need to worry about partial application, also known as currying, too much at first. Just think of the 66 | type after the last arrow as the return value, and the others as the arguments to your function. 67 | 68 | ## Higher Order Functions 69 | 70 | Like JavaScript, functions can take other functions as arguments. (We've already seen how currying lets them return 71 | functions.) 72 | 73 | Let's look at a specialized version of the `List.map` function, which takes a function, and applies it to every element 74 | of a list of Float, returning a new list of Int as a result. 75 | 76 | ```elm 77 | specialMap : (Float -> Int) -> List Float -> List Int 78 | ``` 79 | 80 | The first argument of this function needs to be a function, that takes a Float as a parameter and returns an Int. When 81 | you read this annotation, it may help to say "Float goes to Int" a little bit faster, and then pause. Here, the brackets 82 | *do* matter. This is different than `Int -> Float -> List Int -> List Float`, which takes two numbers and a 83 | list, but never a function. 84 | 85 | We know that `round : Float -> Int`, so we can write: 86 | 87 | ```elm 88 | roundMap : List Float -> List Int 89 | roundMap = specialMap round 90 | ``` 91 | 92 | Even though `roundMap` doesn't take any arguments explicitly to the left of the equals, applying `specialMap` returns a 93 | function thanks to currying. We could also write `roundMap xs = specialMap round xs`; it's really a matter of style. 94 | 95 | ## Type Variables 96 | 97 | If you look at the List library, this isn't actually how 98 | [List.map](http://package.elm-lang.org/packages/elm-lang/core/latest/List#map) is defined. Instead, it has lowercase 99 | type names, which are *type variables*: 100 | 101 | ```elm 102 | List.map : (a -> b) -> List a -> List b 103 | ``` 104 | 105 | This means that the function works for any types `a` and `b`, as long as we've fixed their values, which usually happens 106 | by passing arguments whose types we know. So we could give it a `(Float -> Int)` and a `List Float`, or we could give a 107 | `(String -> Action)` and a `List String`, and so on. (This use of "variable" is closer to algebra than JavaScript, in 108 | that it's something you or the compiler find based on constraints, not explicitly set to whatever you need it to be.) 109 | 110 | By convention, type variables are single letters starting at the beginning of the alphabet, although (almost) any 111 | lowercase string will work. Occasionally it's helpful to use another letter or a descriptive word, especially if you 112 | have more than one type variable. For example, `Dict k v` reminds us that the types variables are the keys and values. 113 | It's possible for a type to have any number of type variables, but more than two is rare. 114 | 115 | Type variables let us write generic code, like lists and other containers that can hold any type of value. Each 116 | particular container can only hold one type, but you get to pick what that is. Then `List.map` can traverse a list and 117 | apply a function to it, without knowing what's in the list. Only the function applied to each element needs to know what 118 | type those elements are. 119 | 120 | If `List a` is a list of any type, what is just `List`? Technically it's called a *type constructor*, but the better 121 | answer is that it's not really anything. It can't really exist on its own. The best way to think of it is that `List a` 122 | is the base type, and sometimes the type variable `a` gets replaced with a real type. 123 | 124 | ## Records 125 | 126 | A record is like a JS object, except you know at compile-time that the fields you access will be there. Also like 127 | JavaScript, they're written with brackets. *Unlike* JavaScript, records values use equals between key and value; when 128 | written with colons, it's a record *type*. Here's a simple record: 129 | 130 | ```elm 131 | point : {x : Float, y : Float} 132 | point = {x = 3.2, y = 2.5} 133 | ``` 134 | 135 | In most cases that's all you need to know about record types. But it's also possible to write functions that work on 136 | records as long as they have the right fields, ignoring any other fields. 137 | 138 | ```elm 139 | planarDistance : {a | x : Float, y : Float} -> {b | x : Float, y : Float} -> Float 140 | planarDistance p1 p2 = 141 | let dx = p2.x - p1.x 142 | dy = p2.y - p1.y 143 | in sqrt (dx^2 + dy^2) 144 | ``` 145 | 146 | The `{a |` part of the annotation indicates a base record, of type `a`, is extended. Then we list the fields it's 147 | extended with, and what their types are. In the simplest cast, `a` can be the empty record, i.e. there are no extra 148 | fields. We use a different type variable, `b`, for the second argument to indicate that the two records don't have to be 149 | the same type. For example: 150 | 151 | ```elm 152 | point3D = {x = 1.0, y = 6.3, z = -0.9} 153 | 154 | dist = planarDistance point point3D 155 | ``` 156 | 157 | ## Constrained types 158 | 159 | Elm has three special type variables that indicate that the value needs to one of a few different types, but not just 160 | any type. 161 | 162 | A `number` is either an `Int` or `Float`. A number literal without a decimal point is a `number`. Numbers support 163 | basic arithmetic (except division, which is handled separately for each type). 164 | 165 | A `comparable` can be a number, character, string, or recursively a list or tuple of comparables. Surprisingly enough, 166 | comparables can be compared with operations like `(>)`. Elm's dictionaries and sets are implemented as binary search 167 | trees, so the keys or elements must be comparable. 168 | 169 | An `appendable` can be a string, text (i.e. with typesetting information), or a list (containing any type). Two 170 | appendables of the same type can be appended with `(++)`. 171 | 172 | To use any of these types, just use their name in an annotation instead of a specific type or type variable. 173 | 174 | If one of these types appears multiple times in a type annotation, all occurrences must resolve to the same type. You 175 | can allow them to be different by sticking something on to the end of the type, like `appendable2` or similar. For 176 | example, if you enter `(4, 2)` into the Elm REPL, it will infer the type `(number, number1)`. The -`1` indicates 177 | that the second number need not be the same type as the first. 178 | -------------------------------------------------------------------------------- /Mailboxes, Messages, and Addresses.md: -------------------------------------------------------------------------------- 1 | ***This essay was written for Elm 0.16 and was made completely irrelevant by 0.17. Unless you have a historical curiosity, do not read this essay, as it will only confuse you.*** 2 | 3 | ---- 4 | 5 | 6 | # Mailboxes, Messages, and Addresses 7 | 8 | *Note: This essay assumes basic familiarity with Elm.* 9 | 10 | In Elm, signals always have a data source associated with them. `Window.dimensions` is exactly what you think it is, and you can't send your own events on it. You can derive your own signals from these primitives using `map`, `filter`, and `merge`, but the timing of events is beyond your control. 11 | 12 | This becomes a problem when you try to add UI elements. We want to be able to add checkboxes and dropdown menus, and to receive the current state of these elements as a signal. So how do we do that? 13 | 14 | ## The Bad Old Days 15 | 16 | An earlier version of Elm offered this approach: 17 | 18 | ```elm 19 | checkbox : Bool -> (Element, Signal Bool) 20 | ``` 21 | 22 | Given an initial state, this function created the checkbox DOM element and the signal of boolean state. The element needed to be placed into the page manually. (It wasn't a signal of elements because it kept the same size whether checked or unchecked.) Then the programmer would use the signal of booleans somewhere in the program. If you knew how many checkboxes you need, and it's more than one, you'd have to do tedious mapping and merging to get a single signal that told you _which_ checkbox got checked. 23 | 24 | Do you see the problem yet? What happens if you have a dynamic number of checkboxes? Maybe you're designing a music player, and you have one checkbox per song but an unknown or variable number of songs? If we try to use `Signal.map` on the old checkbox function, we get a value of type `Signal (Element, Signal Bool)`. This is gross enough already, but the signal of booleans becomes unusable because Elm forbids signals of signals (for complex but good technical reasons). 25 | 26 | The root of the problem is that we're creating one signal for each element. The key idea behind a mailbox is that it's one signal that can receive updates for many elements. That means that a mailbox's signal is _not_ constrained to only one source of data provided by the runtime, the way `Window.dimensions` is. But, creating an event on a signal is an effect, and Elm functions don't have effects (other than their return value). So how do we make this work? 27 | 28 | ## Enter Mailboxes 29 | 30 | Here's the definition of a mailbox: 31 | 32 | ```elm 33 | type alias Mailbox a = 34 | { signal : Signal a 35 | , address : Address a 36 | } 37 | ``` 38 | 39 | So a mailbox is a record with a perfectly ordinary signal, and this new Address thing, which we'll come to in a moment. But first, how do you make a mailbox? Using a function in the `Signal` library: 40 | 41 | ```elm 42 | mailbox : a -> Mailbox a 43 | ``` 44 | 45 | Okay, so this just takes the initial value of the new signal and returns the new mailbox. A few things to note: first, don't use `Signal.map` with this function. That would give you a signal of a record containing a signal, which puts us back into the forbidden world of signals of signals. 46 | 47 | Second, you'll often see type annotations like `myMailbox : Signal.Mailbox MyType`. The period is critically important: it's not a signal of mailboxes, it's just the `Mailbox` type from the `Signal` module. You can get around this with `import Signal exposing (Mailbox)`. 48 | 49 | Third, `mailbox` is one of the few impure functions in Elm. By "pure", we mean that if you call a function with the same arguments, you get the same result. That's true of almost every function in Elm (and _not_ true of functions in other languages that look at global mutable state.) But here, we're cheating: if you call `mailbox myThing` twice, you get two different mailboxes. 50 | 51 | What this means in practice is that you have a specific and constant number of mailboxes in your program. You don't make more dynamically and you typically don't make one inside a function. If you set things up like I'm going to show you, you'll only have _one_ mailbox in your program, or at least only one per module. 52 | 53 | ## Things to do with an Address 54 | 55 | Okay, back to this address thing that we get when we make a mailbox. If you want to know what an address _is_, well, it's an opaque handle that identifies which signal a value should be sent to. There are three ways to use an address to send a value on its signal. 56 | 57 | The first is to make a message. A message is like an envelope, sealed up with a letter and an address written on the front, but not yet sent. You can make a message with this function (again in the `Signal` library): 58 | 59 | ```elm 60 | message : Address a -> a -> Message 61 | ``` 62 | 63 | So yeah, an address, the event to send, and you get a message. (Interestingly, it's just a `Message`, not a `Message a`. We know that every message has a match between the address and the event, and we don't need to know that type to actually send it.) The neat thing about a message is that since it only _describes_ sending a value on a signal, rather than actually sending it, you can send a message as many times as you like. The reason you'd make a message however, is to use it with some other API. Like this function from `Graphics.Input`: 64 | 65 | ```elm 66 | button : Message -> String -> Element 67 | ``` 68 | 69 | We provide the button text and a message to send whenever the button is clicked. The actual sending of the message, the effect, is handled by the runtime. 70 | 71 | It's pretty common to pass along not a message but a function to create one. For example, here's how we make checkboxes in Elm today: 72 | 73 | ```elm 74 | checkbox : (Bool -> Message) -> Bool -> Element 75 | ``` 76 | 77 | The simplest way to get a `Bool -> Message` function is to have a mailbox of booleans, and then do `Signal.message myMailbox.address`. By partially applying `Signal.message`, we're left with a function of exactly the type we want. Usually you'll want your mailbox to track more than just one boolean, and we'll come back to that. 78 | 79 | The second way you can use an address is just pass it along, as with these functions from [elm-html](http://package.elm-lang.org/packages/evancz/elm-html/4.0.1/Html-Events): 80 | 81 | ```elm 82 | onSubmit : Address a -> a -> Attribute 83 | onKeyUp : Address a -> (Int -> a) -> Attribute 84 | ``` 85 | 86 | If you look at these types, and then the type of `Signal.message`, you'll see that they're very similar. Essentially, the library is calling `message` for you, and you provide it the address and the value (or function to make a value). 87 | 88 | ## Taken to Task 89 | 90 | The third and final way you can use an address is to turn it into a task: 91 | 92 | ```elm 93 | send : Address a -> a -> Task x () 94 | ``` 95 | 96 | Notice that this function takes the same arguments as `message` but instead returns a [Task](http://package.elm-lang.org/packages/elm-lang/core/latest/Task). A task is a much more general way to manage effects. A message can only send a value to a signal, but a task can send HTTP requests, interact with local storage, access the browser history, and more. The reason we have messages is to guarantee that clicking a button won't fire off an HTTP request (at least, not directly). 97 | 98 | Like a message, a task doesn't do anything until run. Unlike a message, you can explicitly run a task yourself by sending it out a port: 99 | 100 | ```elm 101 | myMailbox = Signal.mailbox 0 102 | myTask = Signal.send myMailbox.address 1 103 | 104 | port example : Task x () 105 | port example = myTask 106 | ``` 107 | 108 | This is a signal that starts as `0` and then quickly becomes `1`. A more realistic example would send an HTTP request as soon as the program starts, [and then](http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Task#andThen) use the returned value to make another task with `Signal.send` to pipe it back into the program. 109 | 110 | You can also send signals of tasks out of ports, for example, sending a chat room message to the server (which can happen any number of times). 111 | 112 | ## Talk to This Guy 113 | Now that we understand the basics of mailboxes, there's one more function to cover. Here it is (with helpful type variables instead of `a` and `b`): 114 | 115 | ```elm 116 | forwardTo : Address general -> (specific -> general) -> Address specific 117 | ``` 118 | 119 | Okay, looks like a typical mapping function, except–wait a moment–the types are flipped! We can go from specific to general, but turn a general address into a specific one? _What the WHAT??_ 120 | 121 | What's going on here is that the new address doesn't have a signal associated with it. Instead, whenever anybody tries to use it like a "real" address, it applies the function to turn the specific value into a general value, and then sends that along to the general address. 122 | 123 | If that doesn't make sense yet, it's probably best to see an example. 124 | 125 | ## Taking Action 126 | We're going to be writing a very simple spaceship simulator. So simple, in fact, that all we can do is decide whether to direct power to the forward or rear deflector shields, using checkboxes. (Blame budget cuts to NASA.) 127 | 128 | Using the classic [Elm Architecture](https://github.com/evancz/elm-architecture-tutorial), we define our action and model types, as well as the initial model (I use the convention `model0` for this, like the subscript zero in physics equations): 129 | 130 | ```elm 131 | type Side = Forward | Rear 132 | type Action = NoOp | Shield Side Bool 133 | 134 | type alias Model = {forward : Bool, rear : Bool} 135 | 136 | fwd0 = True 137 | rear0 = False 138 | model0 : Model 139 | model0 = Model fwd0 rear0 140 | ``` 141 | 142 | In case you haven't seen it before, the last line uses record constructor syntax, which basically makes a `Model` by passing in the values of the record, in order. Moving on to the mailbox: 143 | 144 | ```elm 145 | myMailbox = Signal.mailbox NoOp 146 | 147 | cbForward = 148 | checkbox 149 | (\b -> Signal.message myMailbox.address (Shield Forward b)) 150 | fwd0 151 | 152 | cbRear = 153 | checkbox 154 | (Signal.message (Signal.forwardTo myMailbox.address (Shield Rear))) 155 | rear0 156 | ``` 157 | 158 | We define the mailbox using the `NoOp` (no operation) tag, and then our two checkboxes. Remember that the first argument to `checkbox` is `Bool -> Message`. In the first example, I use an anonymous function to convert to our action type directly. In the second example, I use `forwardTo` to create a new address that accepts a boolean. `Shield Rear` is a partial application of the `Shield` tag; it's expecting a Boolean and produces an `Action`, which is exactly the specific-to-general function we want. Anyway, both approaches are viable in this case, but `forwardTo` becomes more helpful as you grow larger and more modular applications. 159 | 160 | Finally we define our step function and tie everything together with a `foldp` to keep the model updated. 161 | 162 | ```elm 163 | step : Action -> Model -> Model 164 | step a m = 165 | case a of 166 | NoOp -> m 167 | Shield Forward b -> {m| forward = b} 168 | Shield Rear b -> {m| rear = b} 169 | 170 | model : Signal Model 171 | model = Signal.foldp step model0 myMailbox.signal 172 | ``` 173 | 174 | Both of these are fairly obvious (provided you're familiar with the [record update syntax](http://elm-lang.org/docs/syntax#records)), and there seems to be a lot of clunky boilerplate throughout. But it gets the job done. 175 | 176 | Actually putting the checkboxes onscreen is fairly simple and you can find the entire program in Appendix I. 177 | 178 | ## Transformations 179 | Action types are well and good, but there's another way to construct your program. It's not always better, and it's a little harder to understand, but it also can be more concise and explicit. The basic idea is that rather than having a mailbox of action types, you have a mailbox _of functions_. Specifically, of transformations: 180 | 181 | ```elm 182 | type alias Model = {forward : Bool, rear : Bool} -- same as before 183 | type alias Transformation = Model -> Model 184 | 185 | myMailbox : Signal.Mailbox Transformation 186 | myMailbox = Signal.mailbox identity 187 | ``` 188 | 189 | The first piece of good news is that we no longer need a `NoOp` tag, or even an explicit action type at all. We just use the `identity` function to initialize our mailbox. 190 | 191 | Creating the initial model is the same as before, but the checkboxes are defined very differently: 192 | 193 | ```elm 194 | cbForward = 195 | checkbox 196 | (\b -> Signal.message myMailbox.address (\m -> {m| forward = b})) 197 | fwd0 198 | 199 | cbRear = 200 | checkbox 201 | (\b -> Signal.message myMailbox.address (\m -> {m| rear = b})) 202 | rear0 203 | ``` 204 | 205 | It's like we squished the step function into the message! Each checkbox says how it wants to manipulate the model directly. This is less modular than an explicit action type, but it's still reasonable because it's a record update. You can add more fields to `Model` without breaking this code. 206 | 207 | Finally, all that's left of the step function is just function application. 208 | 209 | ```elm 210 | model : Signal Model 211 | model = Signal.foldp (<|) model0 myMailbox.signal 212 | ``` 213 | 214 | So, we've sacrificed a little bit of modularity and intuition for a dramatic reduction in boilerplate. We also put the UI controls right next to the change to the model that they enact. The full code is in Appendix II. 215 | 216 | ## Handling Dynamic Data 217 | 218 | Earlier, I mentioned that if you were managing many songs, there was no way for the old system to give you one checkbox per song. To hint at how this would work with mailboxes, I'll define an action type and sketch out the model: 219 | 220 | ```elm 221 | type Action = Check SongID Bool | NoOp | ... 222 | myMailbox = Signal.mailbox NoOp 223 | 224 | -- implementation is left for the reader 225 | getSongs : Model -> List SongID 226 | getStatus : Model -> SongID -> Bool 227 | model : Signal Model 228 | ``` 229 | 230 | Then I'll write a function that makes a checkbox for a given song and current checked status. It's this function's responsibility to wrangle `Graphics.Input` into submission. 231 | 232 | ```elm 233 | mkCheckbox : SongID -> Bool -> Element 234 | mkCheckbox id currentStatus = 235 | checkbox 236 | (\b -> Signal.message myMailbox.address (Check id b)) 237 | currentStatus 238 | ``` 239 | 240 | Next, we extract that data we need from the model and make one checkbox per list item. Then we map that function over the signal of the model. 241 | 242 | ```elm 243 | mkCheckboxes : Model -> List Element 244 | mkCheckboxes model = 245 | let songs = getSongs model 246 | statuses = List.map (getStatus model) songs 247 | in List.map2 mkCheckbox songs statuses 248 | 249 | checkboxes : Signal (List Element) 250 | checkboxes = Signal.map mkCheckboxes model 251 | ``` 252 | 253 | This gives me a list of checkboxes that I can put into the view, based on a signal of a list of songs, which varies in both space and time. 254 | 255 | The takeaway of this example is that every time the model updates, `checkboxes` creates a bunch of new checkboxes that will send messages to the same address that has always been there. The old checkboxes are taken offscreen and eventually garbage collected. As the program runs, more and more elements are created that can send events to the mailbox, and that's perfectly fine. 256 | 257 | When implementing, you need to watch for two things. First, you have to feed the checkboxes their own state from the model (that's the purpose of `statuses`). That's because every time you check a box, the model is updated, which causes a new set of checkboxes to be made, hopefully with the newly updated state. Second, you need to ensure that you can uniquely identify which datum the checkbox refers to (the `SongID`). If you have many actions per datum that are controlled by checkboxes, you need to track that too (either as a parameter of `Check` or another `Action`). 258 | 259 | ## The Future? 260 | 261 | So far, I've tried to remain objective in how mailboxes work and can be used. In this section, I'm going to talk briefly about a [proposal I made](https://gist.github.com/mgold/f3527359996fdf295843) which would slightly alter the library to further reduce boilerplate and (hopefully) make it more intuitive. Let me stress that the proposal has not been accepted and might not ever be incorporated into Elm. 262 | 263 | The big change is that `myMailbox.address` would be replaced with a `dispatch : a -> Message` field. It's like `Signal.message` is called on the address for you. How would this change our checkboxes? 264 | 265 | ```elm 266 | -- action type style 267 | cbForward = 268 | checkbox 269 | ((Shield Forward) >> myMailbox.dispatch) 270 | fwd0 271 | 272 | -- transformations style 273 | cbForward = 274 | checkbox 275 | (\b -> myMailbox.dispatch (\m -> {m| forward = b})) 276 | fwd0 277 | ``` 278 | 279 | The action type style benefits tremendously; we replace `forwardTo` with standard function composition. Surprisingly, the transformation style doesn't change much, though it does get a little shorter. 280 | 281 | Even if the proposal is never implemented, I hope this example helps show what messages and addresses truly are underneath the types and functions. 282 | 283 | Hopefully mailboxes make more sense to you now, but frequently even the best explanation can only do so much. If you're still struggling, study and extend the fully-working examples below. Thanks for reading. 284 | 285 | -------------- 286 | 287 | ## Appendix I 288 | This is the code for the traditional "action type" architecture. 289 | 290 | ```elm 291 | import Graphics.Input exposing (checkbox) 292 | import Graphics.Element exposing (flow, down, right, show) 293 | 294 | type Side = Forward | Rear 295 | type Action = NoOp | Shield Side Bool 296 | 297 | type alias Model = {forward : Bool, rear : Bool} 298 | 299 | fwd0 = True 300 | rear0 = False 301 | model0 : Model 302 | model0 = Model fwd0 rear0 303 | 304 | myMailbox = Signal.mailbox NoOp 305 | 306 | cbForward = 307 | checkbox 308 | (\b -> Signal.message myMailbox.address (Shield Forward b)) 309 | fwd0 310 | 311 | cbRear = 312 | checkbox 313 | (Signal.message (Signal.forwardTo myMailbox.address (Shield Rear))) 314 | rear0 315 | 316 | step : Action -> Model -> Model 317 | step a m = 318 | case a of 319 | NoOp -> m 320 | Shield Forward b -> {m| forward = b} 321 | Shield Rear b -> {m| rear = b} 322 | 323 | model : Signal Model 324 | model = Signal.foldp step model0 myMailbox.signal 325 | 326 | scene m = 327 | flow down 328 | [ flow right [cbForward, show "Forward"] 329 | , flow right [cbRear, show "Rear"] 330 | , show m 331 | ] 332 | 333 | main = Signal.map scene model 334 | ``` 335 | 336 | ## Appendix II 337 | This is the code for the "transformations" (signal of functions) style of mailboxes. 338 | 339 | ```elm 340 | import Graphics.Input exposing (checkbox) 341 | import Graphics.Element exposing (flow, down, right, show) 342 | 343 | type alias Model = {forward : Bool, rear : Bool} 344 | 345 | fwd0 = True 346 | rear0 = False 347 | model0 : Model 348 | model0 = Model fwd0 rear0 349 | 350 | myMailbox = Signal.mailbox identity 351 | 352 | cbForward = 353 | checkbox 354 | (\b -> Signal.message myMailbox.address (\m -> {m| forward = b})) 355 | fwd0 356 | 357 | cbRear = 358 | checkbox 359 | (\b -> Signal.message myMailbox.address (\m -> {m| rear = b})) 360 | rear0 361 | 362 | model : Signal Model 363 | model = Signal.foldp (<|) model0 myMailbox.signal 364 | 365 | scene m = 366 | flow down 367 | [ flow right [cbForward, show "Forward"] 368 | , flow right [cbRear, show "Rear"] 369 | , show m 370 | ] 371 | 372 | main = Signal.map scene model 373 | ``` 374 | -------------------------------------------------------------------------------- /Modules, Exports, and Imports.md: -------------------------------------------------------------------------------- 1 | # Modules, Exports, and Imports 2 | 3 | Elm's core libraries are organized into modules, as are any third-party packages you may use. For your own large 4 | applications, you can define your own modules. However defined, you need to import from modules to get useful values and 5 | types for your program. 6 | 7 | After reading this guide you will know 8 | * how to organize many modules within the file system 9 | * how to define a module's interface in a way that permits refactoring without breaking downstream code 10 | * how to use the import statements so you always know where a piece of code came from 11 | * how to organize tests or examples to not interfere with the main codebase 12 | * the best practices and common pitfalls of writing a large Elm codebase 13 | 14 | This shouldn't be the first guide on Elm you read, but if you've playing around for a few hours and have specific 15 | questions about modules and the like, you should be fine. This guide aims to be a comprehensive reference to be read 16 | straight through, but if you have questions about a specific piece of syntax you should do fine skimming for code 17 | blocks. 18 | 19 | ## Packages and Applications 20 | 21 | Elm programs fall into two categories. **Packages** (or **libraries**) are meant to be reused and are typically 22 | published to the [package registry](http://package.elm-lang.org/). **Applications** are programs that can actually be 23 | run and produce output. Applications may depend on packages, which may depend on other packages in turn; applications 24 | are the root of this tree. 25 | 26 | The distinction between package and application occurs in `elm-package.json`: A package will export at least one module 27 | in the `"exposed-modules"` field. Packages are compiled with `elm make` and no additional arguments. This compiles the 28 | modules listed, and subjects them to additional compile-time checks ensuring every exported value and type are 29 | documented properly. The compiler does not generate an HTML or JS output file. 30 | 31 | If you pass a file to `elm make`, then you are writing an application. That file (and therefore module) is known as 32 | "Main". It's not necessary to call this file `Main.elm` or even declare a module definition in it at all -- but you 33 | should for large applications. 34 | 35 | However defined, only Main can define ports (a topic otherwise beyond the scope of this guide). The Main module must 36 | define a `main` value, whose type is restricted to a handful of things that the compiler can display. Other modules 37 | should avoid defining `main`. 38 | 39 | Another difference between packages and applications is how they tolerate change. Elm's package manager enforces 40 | [semantic versioning](http://semver.org/), discouraging breaking changes. Additionally anything that is exported must be 41 | documented. Packages therefore want to hide their type definitions and helper functions, in order to present a stable, 42 | understandable, and helpful interface. Applications are more tolerant of change; for example adding a field to a record 43 | type alias or a tag to a union type. Only the application itself relies on these definitions, and the compiler will find 44 | any discrepancies that changes introduce. Therefore, packages must tightly control what is exported, but applications 45 | can afford to be more permissive. 46 | 47 | ## Modules and Files 48 | 49 | Every file contains exactly one module. *Filenames should be capitalized* and match the name of the module they contain. 50 | For example, `Foo.elm` should declare the module `Foo`. The compiler will not allow module names and file paths to 51 | disagree. 52 | 53 | If you only have one file, it's fine to keep it in the top level folder. Otherwise, you should create a `src` folder and 54 | keep all source files in there. You'll need edit `elm-package.json` to read `"source-directories": [ "src" ],` (don't 55 | forget the comma; `elm package` doesn't give a helpful error on invalid JSON). 56 | 57 | Module names can contain dots, for example `Json.Encode`, which is in file `src/Json/Encode.elm`. Folders may be nested 58 | as deep as you like, but don't overdo it. Sometimes a package will have a primary module `Foo` and a secondary module 59 | `Foo.Bar`. This is just the coincidence of having a file named the same as a folder (except the `.elm` extension); 60 | there's nothing "magic" about it. 61 | 62 | ## Declaring a Module and Its Exports 63 | 64 | The simplest syntax to declare a module is 65 | 66 | ```elm 67 | module MyModule exposing (..) 68 | ``` 69 | 70 | This must be the first line of the file, and the module name must begin with a capital letter. Convention is to 71 | capitalize only the first letter of acronyms (e.g. `Json` and `Http`). 72 | 73 | The `(..)` indicate that you are exporting everything in this module. That is, the parenthesis enclose a list of 74 | exported values, but the two dots are a shortcut indicating that everything is exported. "Everything" comprises all 75 | defined top-level constants, functions, types aliases, union types, and their tags. 76 | 77 | If you want to limit what is exported, you must list everything that you do want to export (there is no way to 78 | "blacklist" private items). A list of items is separated by commas, and may be broken up across many lines. The one 79 | wrinkle is how union types are exported, but that will be addressed below. 80 | 81 | ```elm 82 | module MyModule exposing (MyType, myValue, myFunction) 83 | ``` 84 | 85 | If `MyModule` defines `myPrivateFunction`, it cannot be imported by any other module, regardless of syntax used. 86 | 87 | Although uncommon, you should avoid situations like this: 88 | 89 | ```elm 90 | module Chance exposing (Model, init) 91 | 92 | type Coin = Heads | Tails 93 | 94 | type alias Model = { coin : Coin } 95 | 96 | init : Model 97 | init = Model Heads 98 | ``` 99 | 100 | The private `Coin` type is visible in the definition of the public `Model` type. Even worse, someone importing this code 101 | can actually obtain a value of type `Coin` through `init`, even though that type doesn't exist to them. And worst of 102 | all, the compiler will not catch this error. It *should*, but it doesn't. So be careful when defining types, and think 103 | about what will and will not be exported. 104 | 105 | ## Imports 106 | The most common way to import a module is also the simplest: 107 | 108 | ```elm 109 | import Dict 110 | ``` 111 | 112 | This gives you access to everything in the [Dict 113 | library](http://package.elm-lang.org/packages/elm-lang/core/latest/Dict) by prefacing it with the module name and a dot. 114 | This is sometimes called a **qualified** import. So if you want to use `Dict.insert`, this import statement is sufficient. 115 | 116 | Qualified imports are the preferred way to import values from other modules, because you can always tell where something 117 | came from by the module name right in front of it. Conversely, it makes it easy to tell what is defined in *this* module. 118 | 119 | The alternative to a qualified import is an **exposed** import, because of the keyword `exposing` (whose length should 120 | serve as a deterrent to using it!). But it's usually okay if you list what you're exposing, for example: 121 | 122 | ```elm 123 | import Dict exposing (Dict) 124 | import Html exposing (div, span, h1, h2) 125 | ``` 126 | 127 | In the first case, the `Dict` in parentheses is a type, not the module. (It's very common for modules to define types of 128 | the same name as the module itself.) It avoids the need to say `Dict.Dict` in type annotations. In the second case, the 129 | functions being exposed have distinctive names, and are going to be used frequently. 130 | 131 | In both cases, the module name is also available to be use qualified. So you can still use `Dict.insert` or `Html.text`. 132 | When you have a list of exposed imports, the order doesn't matter, but typically the types are listed before the values. 133 | 134 | The real reason exposed imports are considered an antipattern is because they can be combined with `(..)` to dump the 135 | entire module into the current one. When there are multiple such imports, it becomes impossible to see where something 136 | came from, and the odds of a name collision is much higher. 137 | 138 | ```elm 139 | -- Antipattern! 140 | import Dict exposing (..) 141 | ``` 142 | 143 | `Dict.insert` will now be available as `insert`. This can easily be confused with other insert operations, although the 144 | compiler will stop you in truly ambiguous cases. So don't expose an entire module unless you're really sure about it. 145 | 146 | Regardless, exposing happens when you import. This makes it different from exporting, which happens when modules are 147 | defined. Many people and even Elm's tooling conflate the two, but if you're being technical they are distinct. 148 | 149 | Infix operators must be imported exposed, for example as `import Json.Encode exposing (object2, (:=))`. Note that infix 150 | operators need to be surrounded by extra parentheses. The language does not have syntax for qualified infix operators. 151 | The good news is that, with the exception of the previous example, all infix ops in core are imported exposed by 152 | default. 153 | 154 | Specifically, all of the arithmetic operators are in 155 | [Basics](http://package.elm-lang.org/packages/elm-lang/core/latest/Basics), which is imported exposed automatically. 156 | (It's worth becoming familiar with everything in that module.) List cons, `(::)`, is imported along with the `List` 157 | type. Als imported are are `Maybe` and `Result`, including their tags, `Just`, `Nothing`, `Ok`, and `Err`. 158 | 159 | When importing a module, you can rename it like so: 160 | 161 | ```elm 162 | import Json.Decode as Decode 163 | import Graphics.Element as Elem exposing (Element, show) 164 | ``` 165 | 166 | As you can see, renaming and exposing can be used together. If you do though, `as Alternative` needs to come before 167 | `exposing (the, functions)`. 168 | 169 | Renaming is often used by "-extra" packages, which add extra functions to the core library. Typically they will be 170 | namespaced according the library they extend, and then imported like this: 171 | 172 | ```elm 173 | import Random 174 | import Random.Extra as Random 175 | ``` 176 | 177 | Yes, you can rename an import to share a name with another module. In theory, you now no longer need to worry about 178 | which functions `Random` exports, and which ones `Random.Extra` does (until you need to look up documentation…). 179 | However, some of these libraries will re-export functions in the library they extend, with the same name. Then when you 180 | try to use this function, the compiler will error because `Random.map` is ambiguous. There is no way to resolve this 181 | error without renaming the import or updating the library. 182 | 183 | When you're listing all of your imports, it's helpful to group them in a sensible order. Although you don't have to be 184 | neurotic about it, try to put core libraries towards the top, and third-party packages towards the bottom. Modules from 185 | the current package or application should be listed last. 186 | 187 | ## Exporting and Importing Union Types 188 | Union types have a little bit of special treatment when it comes to imports and exports. Let's start with a simple union 189 | type, which you might find in a counter demo. 190 | 191 | `type Msg = Increment | Decrement` 192 | 193 | Remember that `Increment` and `Decrement` are called "tags". How would we export this type? 194 | 195 | `module MyModule exposing (Msg)` exports `Msg` only. That is called an *opaque type*. Clients can see that `Msg` 196 | exists, but they can't see into it. This is frequently what you want, and we'll talk about it more in the next section. 197 | 198 | `module MyModule exposing (Msg(..))` exports `Msg` and all of its tags, namely `Increment` and `Decrement`. This form 199 | can be useful sometimes if you can commit to keeping `Msg` the same. A good example is a [nonempty 200 | list](http://package.elm-lang.org/packages/mgold/elm-nonempty-list/latest/List-Nonempty#Nonempty); there will never be a 201 | reason to change the type's definition so the tag can be safely exported. 202 | 203 | `module MyModule exposing (Msg(Increment, Decrement))` exports `Msg` and only the listed tags. In this case it's 204 | listing all the tags explicitly. It's possible to only export *some* of the tags, but there is no reason to do this, 205 | ever. 206 | 207 | The trouble with exporting tags is not only that you may want to remove some, which will break any code that relies on 208 | the ones being removed. Even adding tags will break code, because previously exhaustive pattern matches are no longer 209 | exhaustive. If only some of the tags are exported, it's impossible to write a valid `case` statement (at least not 210 | without a `_ ->` pattern, which are discouraged). 211 | 212 | Importing union types exposed follows the exact same syntax. For example, `import MyModule exposing (Msg)` will 213 | import only the type, while `import MyModule exposing (Msg(..))` will import any exported tags as well. You can 214 | also use exported tags qualified, like `MyModule.Increment`. 215 | 216 | ## Opaque Types 217 | 218 | An **opaque type** is a union type where the type is exported but the tag(s) are not. Someone outside the module can see 219 | that the type exists, pass it around, and store it in records. They only thing they *can't* do is look inside the type, 220 | even if they know what the tags are named. Hence, it's opaque. 221 | 222 | An example of an opaque type would be a 2D point. Creating a point would require either `x` and `y`, or `r` and `theta`. 223 | But, there's no way to know which version is actually stored.. The point might actually store all four, knowing that 224 | there's no way for someone to create a point that's inconsistent. Rather than rely on record accessors, the author of 225 | the `Point` library would define their own methods to access the coordinates of the point. 226 | 227 | What this means is that opaque types are Elm's way of enforcing information hiding. They allow a package author to 228 | define an interface of functions to create, update, and read useful values out of the opaque type. The implementation 229 | can change completely, but as long as all functions on the type are updated to match, it's still considered a patch 230 | change. This gives package writers flexibility when writing their libraries. It also lets them rely on invariants, 231 | assured that the client hasn't meddled with values of the type in unexpected ways. 232 | 233 | Opaque types are less useful in applications. If you're typing to simply pass information around, exporting record type 234 | aliases is fine. If it makes sense to also define operations on these models, an opaque type might be a better fit. 235 | 236 | If your union type contains many tags, you can export functions that wrap them. You can be selective about which ones 237 | you export. Sometimes it can be tedious, but it's worth it. 238 | 239 | ```elm 240 | module Road exposing (Msg, addCar, redLight) 241 | 242 | import Car exposing (Car) 243 | 244 | type Light = 245 | Red | Yellow | Green 246 | 247 | type Msg = 248 | AddCar Car | Light Light | SomethingPrivate 249 | 250 | addCar : Car -> Msg 251 | addCar = 252 | AddCar 253 | 254 | redLight : Msg 255 | redLight = 256 | Light Red 257 | ``` 258 | 259 | You cannot make an opaque type out of a type alias; those are either exported or not, just like values. But you can 260 | create a union type to hide it. (This is more common when the opaque type represents a model rather than a message.) 261 | 262 | ```elm 263 | module Person exposing (Person, age) 264 | 265 | type Person = 266 | P { name : String, age : Int } 267 | 268 | age : Person -> Int 269 | age (P {age}) = 270 | age 271 | ``` 272 | 273 | First, we define the union type `Person` with one tag, `P`, which carries a record. (You can put the record definition 274 | directly in the union type, or define an unexported alias.) Then we can export the `age` function which accesses the 275 | record in a way not possible outside of this module. The definition uses two nifty language features. First, it pattern 276 | matches on the `P` tag in the argument list. This is permitted when there is only one tag, because otherwise it's an 277 | incomplete pattern match. Next, `{age}` destructures the record, assigning the local constant `age` to the value of the 278 | record's `age` field. It's a much more concise way of writing this: 279 | 280 | ```elm 281 | age person = 282 | case person of 283 | P record -> 284 | record.age 285 | ``` 286 | 287 | ## Organizing Tests and Examples 288 | 289 | When writing a package, it's often useful to write tests or examples that use it. But, you don't want these to be 290 | included with the package, and certainly not in the compiled code that uses your package. Elm's tooling does not 291 | (currently) have an equivalent of Node's dev-dependencies or Ruby on Rails' development environment. So here is a trick 292 | to keep tests and their libraries separate from your package, while still being able to run the tests without 293 | publishing. 294 | 295 | Create a new folder, say `test`, and copy `elm-package.json` there. Edit it and make these changes: 296 | * Change the version to `0.0.1`. This isn't strictly necessary but it helps prevent the tests from being released as their own package. 297 | * Under `"source-directories"`, change `"src"` to be `"../src"`. (If it's just `"."`, make it `".."`). Then add `"."` to the list. 298 | * Change the `"exposed-modules"` to be the empty list, `[]`. Tests are an application, after all. 299 | 300 | Notice that we've kept all of the dependencies of the package in place. Now you can install any test toolkits you like 301 | into `test/elm-package.json` and they won't affect the main package. If the package's dependencies change, you will need 302 | to manually sync them to `test/elm-package.json`. 303 | 304 | You can now write your tests or examples and import modules in your package as if it was installed in 305 | `elm-package.json`, but instead it's pulling from the parent folder with the original source. You just need to run `elm 306 | package` or `elm reactor` from inside the `test` folder. 307 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elm-for-js 2 | Community driven Elm guide for JS people 3 | 4 | This guide will augment the official Elm docs as needed, for a smooth transitions for people coming from JavaScript. 5 | 6 | ## Getting started 7 | 1. Try the [Hello World](http://elm-lang.org/try) online 8 | 2. Install Elm via [npm](https://www.npmjs.com/package/elm) or the [installer](http://elm-lang.org/install). 9 | 3. Get Hello World [running locally](https://github.com/elm-guides/elm-for-js#getting-hello-world-running-locally) 10 | 4. Work through the [architecture examples](https://github.com/evancz/elm-architecture-tutorial/#the-elm-architecture). Type manually, look in `examples/` for help. 11 | 12 | ## Getting Hello World running locally 13 | 1. Install Elm 14 | 2. Create a new file `Main.elm` in a new folder. 15 | 3. `$ elm package install` to set up `elm-package.json` and `elm-stuff/` for deps (similar to node). 16 | 4. Paste the source from the [Hello World example](http://elm-lang.org/examples/hello-html) to your local `Main.elm` file. 17 | 5. `$ elm package install evancz/elm-html` to install the missing package dependency. 18 | 6. `$ elm-reactor` to get the dev server running at `http://0.0.0.0:8000/`. 19 | 7. Success! 20 | 8. For a standalone file you can run `$ elm make Main.elm --output=main.html` (default is a JS file). 21 | 22 | ## Type Annotations 23 | 24 | Writing them is optional, but highly encouraged. Type annotations improve code by helping you think about what the function should be doing, and serve as compiler-verified documentation. In addition, if you ever want to publish a third-party library, you need type annotations. 25 | 26 | ```elm 27 | -- A variable of type Int. 28 | answer : Int 29 | answer = 42 30 | 31 | -- An update function that takes 2 params - an Action, then a Model and returns a Model (last). 32 | update : Action -> Model -> Model 33 | ``` 34 | 35 | In JavaScript, params are handled at the same time. In Elm, they are [curried](https://gist.github.com/jamischarles/3c22acd58e6d4ab26a41). For example: 36 | ```elm 37 | -- Update is a function that will take an Action param, and return a function that will take a Model param. THAT fn will return a Model. 38 | update : Action -> Model -> Model 39 | ``` 40 | 41 | ## Great elm articles 42 | - [Building a signup form in Elm](http://noredinktech.tumblr.com/post/129641182738/building-a-live-validated-signup-form-in-elm) 43 | 44 | If you see mistakes, or something you want covered, open an issue or a PR. 45 | 46 | ## TODO: 47 | Add sections for 48 | - [x] Package management (compare to node_modules, npm) 49 | - [x] Type Annotations 50 | - [ ] Data types (try not to duplicate official docs) 51 | - [ ] Basic Syntax 52 | - [ ] Program structure and flow 53 | - [ ] How to read the API docs 54 | - [ ] Package catalog link. 55 | -------------------------------------------------------------------------------- /Scope.md: -------------------------------------------------------------------------------- 1 | # Scope in Elm 2 | In Elm as in JavaScript, **scope** refers to what is defined, and where. It is the answer to the question, "where did 3 | this thing come from?", which you will ask constantly when reading examples or someone else's code. Scope also can tell 4 | you why something *isn't* available, what code defines similar values, and where you can find documentation. 5 | 6 | Scope in Elm is often simpler than in other languages because ordinary values do not change over time. Not counting 7 | syntax (e.g. `if`, `->`, and brackets), pretty much everything in Elm is either a literal, something you imported, or 8 | something you defined. 9 | 10 | ## Literals 11 | These are pretty simple, and most are identical or very similar to JS. The types of literals are built into the 12 | language. 13 | 14 | ```elm 15 | True : Bool 16 | 17 | 42 : Int 18 | 6.28 : Float 19 | 20 | "hello" : String 21 | 'x' : Char 22 | 23 | ["welcome", "to", "elm"] : List String 24 | ``` 25 | 26 | ## Imports 27 | Elm's core library is divided into many modules, and any third-party library you are using will also be broken up into 28 | modules. The most common way to import a module is also the simplest: 29 | 30 | ```elm 31 | import Dict 32 | ``` 33 | 34 | This gives you access to everything in the [Dict 35 | library](http://package.elm-lang.org/packages/elm-lang/core/latest/Dict) by prefacing it with the module name and a dot. 36 | So if you see `Dict.insert`, this is where it comes from. 37 | 38 | For values, this is preferred because names are not unique across modules. In fact, they are deliberately consistent. 39 | For example, the Array, Set, and Dict modules all expose an `empty` value, so the module names help you tell them apart. 40 | 41 | For types, things aren't as nice. It's extremely common for a module to export a type of the same name as the module 42 | itself. If you don't want to keep talking about `Dict.Dict` in your type annotations, use 43 | 44 | ```elm 45 | import Dict exposing (Dict) 46 | ``` 47 | 48 | The `Dict` in parentheses refers to the type, not the module. All the module-scoped values like `Dict.insert` are still 49 | available. You can expose multiple values and types from a module by separating them with commas inside the parentheses. 50 | You can find more details in [this guide](/Modules%2C%20Exports%2C%20and%20Imports.md), but this practice in general is discouraged. (This is why the language 51 | forces you to type the long `exposing` keyword.) 52 | 53 | Elm also imports some values and types by default. The full list is 54 | [here](http://package.elm-lang.org/packages/elm-lang/core/latest/#default-imports), but the most important thing to know 55 | is that all of [Basics](http://package.elm-lang.org/packages/elm-lang/core/latest/Basics) is imported exposed. The List, 56 | Maybe, and Signal modules and types are also available to you without an explicit import. 57 | 58 | ## Top-Level Definitions 59 | The following code is valid Elm and JS: 60 | 61 | ```elm 62 | answer = 42 63 | ``` 64 | 65 | In JS, `answer` is a global variable, but best practice is to use `var` and function scope so that it's no longer 66 | global. Elm is immutable, so while it's still global, it's no longer a variable. It can't vary. Therefore, having it 67 | global (at least to the module) is harmless. 68 | 69 | In JavaScript, functions can either be declared or assigned to variables. 70 | 71 | ```javascript 72 | function add(a, b){ return a + b } 73 | var add = function(a, b){ return a + b } 74 | ``` 75 | 76 | These two lines of JS do subtly different things, thanks to hoisting, and in both cases the definition of `add` is 77 | mutable. In some ways, the following two snippets of Elm code also preserve the distinction between declaring a named 78 | function, and assigning an anonymous function to a named variable. However, they behave identically. 79 | 80 | ```elm 81 | add a b = a + b 82 | add = \a b -> a + b 83 | ``` 84 | 85 | Note that `\arg1 arg2 -> expression` is Elm's syntax for anonymous functions. The backslash is traditionally pronounced 86 | *lambda*, after the Greek letter used by programming language theorists, but you're welcome to say *function* if that 87 | helps you. 88 | 89 | You can also define types at the top level, like `type alias Model = Int`. 90 | 91 | ## Local Definitions 92 | 93 | The most common form of a local definition is a function argument. Exactly like JavaScript, any argument is visible from 94 | anywhere inside the function. 95 | 96 | The other form of local definitions are created using a `let... in...` statement. In this example, some values are 97 | function arguments, some are defined in the `let`, and some (the math operators) are imported automatically from Basics. 98 | (And `2` is a literal.) 99 | 100 | ```elm 101 | distanceFrom (originX, originY) (x, y) = 102 | let dx = x - originX 103 | dy = y - originY 104 | in sqrt (dx^2 + dy^2) 105 | ``` 106 | 107 | After the `let`, you can place as many definitions as you like, just like at the top level. They can be fixed values or 108 | functions. You can even write type annotations, although you can't define new types. 109 | 110 | The expression after the `in`, where all the definitions are in scope, is what the entire `let` expression becomes. 111 | Actually, the definitions are in scope even as you write more definitions. Here's a somewhat contrived example. 112 | 113 | ```elm 114 | radToDeg rad = 115 | let piInDegrees = 180 116 | conversionFactor = piInDegrees/pi 117 | in conversionFactor * rad 118 | ``` 119 | 120 | Be aware that if you define the same name multiple times, the innermost definition is used. Usually you should just 121 | avoid the issue entirely by using unique names. 122 | 123 | ```elm 124 | foo = 0 125 | 126 | silly foo = 127 | let foo = 12 128 | in foo 129 | 130 | silly 5 == 12 -- True 131 | ``` 132 | 133 | ## Capitalized Values 134 | 135 | Usually, capitalization indicates a type. [Type annotations](/How%20to%20Read%20a%20Type%20Annotation.md) exist as a miniature 136 | language separate from regular Elm code. But there are two ways that capitalized values can slip into actual Elm code. 137 | 138 | The first is a record type alias. If I define `type alias Point2D = {x : Float, y : Float}`, then like any type alias 139 | `Point2D` becomes a valid type to use in annotations. But because we're aliasing a record, we also gain a *record 140 | constructor*, `Point2D : Float -> Float -> Point2D`. For example, `origin = Point2D 0 0` becomes legal, and this is 141 | actual Elm code, not an annotation. `Point2D` is both a type and a function. 142 | 143 | The second are the tags of a union type. For example, as tree: `type Tree a = Leaf | Node a (Tree a) (Tree a)`. Each tag 144 | becomes a value or function (depending on whether it takes any arguments). In this case, we get the value `Leaf : Tree 145 | a` and `Node : a -> Tree a -> Tree a -> Tree a`. It's these tags, not the `Tree` type, that are used as pattern matches 146 | in `case` statements. Although less common, it's possible to define a union type with a tag the same name as the type. 147 | In that case, that name would be both a type and a value or function. 148 | 149 | ## .accessors 150 | 151 | Finally, record accessors. Uniquely these functions are defined by a pattern, rather than being listed somewhere. For 152 | example, `.name : { b | name : a } -> a`, which basically means `.name` takes any record with a `name` field and 153 | extracts its value. You can use any record field name you like. 154 | 155 | Beware of creating data structures with record accessors. Because all a list's elements must have the same type, each 156 | record accessor must extract a value of the same type, which is usually not what you want. 157 | ```elm 158 | [.name, .number] : List ({ b | name : a, number : a } -> a) 159 | ``` 160 | -------------------------------------------------------------------------------- /Where Did Null And Undefined Go.md: -------------------------------------------------------------------------------- 1 | # Where did `null` and `undefined` go? 2 | 3 | In our applications it is often useful to be able to represent the possible 4 | absence of a value. In JavaScript we have `undefined` to represent the result 5 | of trying to access something that was never defined to begin with, and we have 6 | `null` to assign to values that _might_ have a value but could also be empty. 7 | These two are often conflated and used interchangeably both at the core language 8 | level and in libraries, but both are used to communicate the lack of a value 9 | where it is possible to find one. 10 | 11 | For example, consider the function `Array.prototype.find` which is defined in 12 | the ECMAscript 2015 spec: 13 | 14 | ```javascript 15 | const array = [1, 2, 3, 4, 5]; 16 | const foundOne = array.find((x) => x === 1); // foundOne === 1 17 | const foundSix = array.find((x) => x === 6); // foundSix === undefined 18 | ``` 19 | 20 | The return value of the `find` method in this scenario is either a `number`, or 21 | `undefined` to indicate to us that the item we are looking for is not present 22 | in the array. This type of API, and the presence of values like `null` and 23 | `undefined` in our programming language put the idea of emptiness on an 24 | equivalent level to the concept of the value of a variable. In dynamic languages 25 | like JavaScript this is a trivial outcome of the dynamic type system. In typed 26 | languages like C# the concept of emptiness requires additional type information 27 | to denote, but the same rules apply: a variable of a type, provided it is 28 | allowed to be `null`, can be `null` at any time. 29 | 30 | This requires us as programmers to perform checks when we expect a value 31 | might be `null` or `undefined`. Humans are not perfect, therefore a major 32 | category of bugs manifests itself such as the Null Reference Error when we 33 | forget to check or incorrectly expect that a value will never be null. 34 | 35 | ## `null` is not allowed in Elm 36 | 37 | In Elm, values have types and those types are absolutely static. If a function 38 | expects an `Int` argument, the program will only compile if that function is 39 | only called with `Int` values. This prevents us from calling that function with 40 | `String` values, etc., but it also precludes the situation explained earlier 41 | where the value might be `null` or `undefined`. Not only are `null` and 42 | `undefined` not included as a part of Elm, they wouldn't work regardless because 43 | `undefined` and `null` are not of type `Int` or any other type. 44 | 45 | ## `Maybe` arises from these properties of Elm 46 | 47 | Even though we no longer have a concept of `null` and `undefined`, we still need 48 | to be able represent optional values. Consider again the scenario where we want 49 | to attempt to find an element in an Elm `List Int`, as opposed to the JavaScript 50 | array. We still may not find the thing we were looking for, and since Elm types 51 | are static we need a single type to represent the possible absence of the `Int` 52 | we are trying to find. `Maybe` is that type. Furthermore, because types are 53 | static, a function which returns an `Int` rather than a `Maybe Int` will 54 | _always_ return an `Int`, so there is never uncertainty or need for unnecessary 55 | `null` checks. The `Maybe` type fully describes the presence of an optional 56 | value. 57 | 58 | ## `Maybe` in Elm 59 | 60 | In the language nomenclature, `Maybe` is a type constructor, meaning its full 61 | signature is `Maybe a`. Here, `a` stands in for any other type and indicates to 62 | us that `Maybe` is really a container for other types that serves to add some 63 | additional meaning to a value: whether or not the value we want is present. 64 | Additionally, `Maybe` is a union type, and in fact its full definition is as 65 | simple as: 66 | 67 | ```elm 68 | type Maybe a = Just a | Nothing 69 | ``` 70 | 71 | By defining this, we are establishing a type, `Maybe a`, and two possible _type 72 | constructors_ for that type, `Just a` and `Nothing`. Invoking either type 73 | constructor like a function or value will give us a `Maybe` value which is the 74 | particular member that we used to construct. If we want to represent a non-empty 75 | value of 5, we can invoke `Just 5` to get a `Maybe Int`. If we don't have a 76 | value, we simply pass around `Nothing` since it has no arguments. 77 | 78 | As a union type, `Maybe` is also a data structure in the same way as `List`. 79 | `Maybe` is a container for a single element, and as a container we are able to 80 | define a couple functions that are available for container structures like 81 | `List` and `Task`. 82 | 83 | #### `map` 84 | ```elm 85 | map : (a -> b) -> Maybe a -> Maybe b` 86 | ``` 87 | 88 | Given a `Maybe a` value, transform its contained item from `a` to `b` in 89 | the case that it is `Just a`, and pass through if it is `Nothing`. 90 | 91 | #### `andThen` 92 | 93 | ```elm 94 | andThen : Maybe a -> (a -> Maybe b) -> Maybe b 95 | ``` 96 | 97 | Given a `Maybe a`, chain a computation which produces a new `Maybe b` from the 98 | contained element when the value is `Just a`, and pass through `Nothing` when it 99 | is `Nothing`. This allows us to chain multiple `Maybe`-production computations 100 | together without worrying about `null` checks along the way. If any of the 101 | `Maybe` values in the chain are `Nothing` we will get `Nothing` back without 102 | error. 103 | 104 | `Maybe` also falls into a group of types where some possibilities are 105 | represented and one of those possibilities is most often of primary interest. In 106 | the case of `Maybe`, it's most common to be interested in working with the value 107 | under the `Just` case. Types with this property often come with a `withDefault` 108 | function for collapsing the `Maybe` using some acceptable default value. 109 | 110 | #### `withDefault` 111 | 112 | ```elm 113 | withDefault : a -> Maybe a -> a 114 | ``` 115 | 116 | Given a default value of type `a` and some `Maybe a`, return either the value 117 | contained by the `Maybe` when it is `Just a` or the default value when it is 118 | `Nothing`. 119 | 120 | ## Illustrating `Maybe` by example 121 | 122 | Let's return once more to finding an item in a list. To build a basic function 123 | to find an element in a `List Int`, we can start with 124 | the following type signature: 125 | 126 | ```elm 127 | find : Int -> List Int -> Maybe Int 128 | ``` 129 | 130 | We should read the type signature as "`find` is a function which accepts an 131 | `Int` and a `List` of `Int`s and returns a `Maybe Int`". In the JavaScript 132 | example, `find` returns either a number or `undefined` if the value isn't 133 | in the array. In Elm, we must always return the same type from a function 134 | regardless of the outcome of the logic. We can use the two members of `Maybe`, 135 | `Just` and `Nothing`, to handle the two possibilities and still maintain type 136 | consistency. 137 | 138 | ```elm 139 | find : Int -> List Int -> Maybe Int 140 | find valueToFind listToSearch = 141 | case listToSearch of 142 | currentItem :: remainingItems -> 143 | if currentItem == valueToFind then 144 | Just currentItem 145 | else 146 | find valueToFind remainingItems 147 | 148 | [] -> 149 | Nothing 150 | ``` 151 | 152 | We've defined `find` recursively, and used pattern matching to search the list. 153 | The first case, `currentItem :: remainingItems`, is matched when there is at 154 | least one value in the list, and makes available the item at the front of the 155 | list, `currentItem`, and another list `remainingItems` which is everything else 156 | in that list. If there was one item left, then `remainingItems` will be an empty 157 | list. Now that we have access to the front item, we can check if it's equal to 158 | the one we're trying to find. If it is, we can return `Just currentItem`, which 159 | is of type `Maybe Int` and represents the case where we do have the item of 160 | interest. If it isn't equal, we continue our search over the remaining items 161 | recursively. 162 | 163 | The base case of our recursion is that when there is nothing left in the list. 164 | We've exhausted every possibility and found nothing that matches. In this case 165 | we return the aptly named `Nothing`, which is also of type `Maybe Int` in this 166 | context, but has no data associated with it because we've got no information to 167 | return. 168 | 169 | So far there's not a lot of difference between our function's return value and 170 | one in JavaScript that returns a number or `undefined`. The semantics are 171 | roughly the same, and the main difference has been the implementation details of 172 | using a single type in Elm vs. multiple types in JavaScript to represent value 173 | vs. lack of value. The real difference for Elm programs comes in the way that 174 | `Maybe` is handled. 175 | 176 | ## Dealing with a `Maybe` value 177 | 178 | In JavaScript the language imposes no expectation on how we invoke and use 179 | values, whether they might be `undefined`, `null`, or some real value because 180 | the language is dynamic. From the first example, we could continue on to use 181 | `foundSix` as a number even though it is not, and introduce bugs into our 182 | program. 183 | 184 | ```javascript 185 | const shouldBeSeven = foundSix + 1; // shouldBeSeven is NaN 186 | ``` 187 | 188 | This case is easy to miss because it is the programmer's responsibility to 189 | understand that the value might not be a number. Recall, though, that in Elm 190 | `Maybe` is defined to be a union type. This means that in order to work with it 191 | we must pattern match, and in doing so we must consciously acknowledge every 192 | possible pattern that we can encounter. Further more, we can't attempt to 193 | fraudulently add a `Maybe Int` to another `Int` because the compiler doesn't 194 | know how to add those two types together. The operation doesn't make logical 195 | sense, and instead of reflecting that fact at run-time through a construct like 196 | `NaN`, the compiler simply refuses to compile the code. 197 | 198 | To attempt to add 1 to the result of our search for 6, we must first check that 199 | we found 6 at all and in doing so handle both the case where we were successful 200 | and the case where we were not. 201 | 202 | ```elm 203 | foundSix : Maybe Int 204 | foundSix = 205 | find 6 [1, 2, 3, 4, 5] 206 | 207 | shouldBeSeven : Maybe Int 208 | shouldBeSeven = 209 | case foundSix of 210 | Just value -> 211 | value + 1 212 | Nothing -> 213 | Nothing 214 | ``` 215 | 216 | In the above example we need to match on `Just` in order to extract the value if 217 | it is available. This leaves only one other possible pattern, `Nothing`, and we 218 | just pass through another `Nothing`. Elm has raised the concept of emptiness 219 | from something like `null` that could occur in any variable and brought it 220 | outside the actual data type of the value we want to use. It adds that 221 | information on top of the underlying value and forces us to deal with both cases 222 | via pattern matching. 223 | 224 | Note also that in the above example we simply passed through for the `Nothing` 225 | case. In this case we are passing `Nothing` straight through and only interested 226 | in transforming the value under `Just`. This case is handled for us more 227 | succinctly by `Maybe.map`. We could rewrite the code as 228 | 229 | ```elm 230 | shouldBeSeven : Maybe Int 231 | shouldBeSeven = 232 | Maybe.map (\value -> value + 1) foundSix 233 | ``` 234 | 235 | ## What about representing failed operations? 236 | 237 | In JavaScript `null` and `undefined` are sometimes used to encode the fact that 238 | an operation has or has not successfully completed. Consider the canonical 239 | Node.js callback style: 240 | 241 | ```javascript 242 | function callback(err, data) { 243 | if (err) { 244 | // ...handle error case 245 | } else { 246 | // ... error is null or undefined so we know everything is Ok 247 | } 248 | } 249 | ``` 250 | 251 | The absence of an error indicates that there was no error. In Elm we could write 252 | a similar function that might look like this: 253 | 254 | ```elm 255 | callback : Maybe MyError -> Maybe MyData -> MyOutput 256 | callback maybeError maybeData = 257 | case maybeError of 258 | Just error -> 259 | -- ... 260 | Nothing -> 261 | case maybeData of 262 | Just data -> 263 | -- ... 264 | Nothing -> 265 | -- ... 266 | ``` 267 | 268 | This kind of handling is extremely awkward in Elm, and writing this way discards 269 | what we've already learned about using `Maybe` to represent emptiness. 270 | Furthermore, there is no reason our function must accept exactly one `Just 271 | MyError` or `Just MyData` and one `Nothing`, making this pattern unpredictable. 272 | To deal with cases like this Elm's core libraries also provide the `Result` type 273 | to allow us to represent the possibility of a failure to return something the 274 | same way would use `Maybe` to represent having nothing to return. The definition 275 | of `Result` is also familiar: 276 | 277 | ```elm 278 | type Result a b = Err a | Ok b 279 | ``` 280 | 281 | We once again have two type constructors to represent two possibilities. On one 282 | side we have the `Err` case and any data type we'd like to associate with error, 283 | and on the other we have `Ok` and a data type that we are interested in 284 | computing. We can then pattern match once to handle both cases and have access 285 | to the information in either case. Like `Maybe`, we also know that if a function 286 | doesn't return a `Result` then there is no possibility its computation will fail 287 | and we can be confident in calling it without safeguards and error handling. 288 | Let's reimagine the previous node-style callback example using `Result`: 289 | 290 | ```elm 291 | callback : Result MyError MyData -> MyOutput 292 | callback result = 293 | case result of 294 | Err error -> 295 | -- error is a value of type MyError 296 | Ok data -> 297 | -- data is a value of type MyData 298 | ``` 299 | 300 | `Result` is most commonly found in the core libraries when working with 301 | `Json.Decode` functions, as parsing JSON is something that may fail at runtime 302 | if the input is malformed. We can't detect that the input is malformed at 303 | compile time, and Elm does not provide a concept of exceptions and `try/catch` 304 | so we can use `Result` to model the output. 305 | 306 | ## Conclusions 307 | 308 | Languages like JavaScript handle the concept of emptiness with low-level values 309 | like `null` and `undefined`, and may also use those to represent failure and 310 | success. These concepts are hard to represent in a statically typed language 311 | without introducing a common class of bugs. Elm uses container types to bring 312 | the concepts of emptiness and failure outside of values and add that information 313 | to a type instead of interleaving it. Instead of having a value which might be a 314 | number or `null`, we have `Just` a number or `Nothing`, and the compiler helps 315 | us deal with that. Instead of representing failure and success by emptiness or 316 | resorting to an exception system, we have either an `Err` with some information, 317 | or some `Ok` data. 318 | --------------------------------------------------------------------------------