Explictly deal with all user interactions and state changes function update(action, state) { switch (action.type) { case 'NEW_USER': return Object.assign({}, state, { user: { name: action.name } }); } }
type Filter = ShowAll | ShowCompleted | ShowActive showTodos : Filter -> List Todo -> List Todo showTodos filter todos = case filter of ShowAll -> todos ShowCompleted -> List.filter (\t -> t.complete) todos ShowActive -> List.filter (\t -> not t.complete) todos
Union Types ! They can be checked by the compiler (typos are spotted) ! Compiler ensures all are dealt with in case ... of ! Easy to change / add a new one: add it and fix each compiler error!
Type aliases type alias Person = { name : String , age : Int } incrementAge : Person -> Person incrementAge person = { person | person.age = person.age + 1 }
! Clearer code, typed in your domain specific objects. ! Compiler can guarantee you're meeting the type requirements. ! No more 'undefined is not a function' !
Sweet, sweet Elm let person = { name = "Jack", age = 24 } in incrementAge person ! person is untouched ! incrementAge has to return a new person ! goodbye mutation bugs
Pure Functions Elm functions are always pure. let sum = (a, b) => a + b; //PURE sum(2, 2) // => ALWAYS 4 let otherSum = (a, b) => window.foo + a + b; //IMPURE otherSum(2, 2) // => who knows, dependent on window.foo
Get the first thing from the list, and double it2 let list = [1, 2, 3] in (List.head list) * 2 But what if list = [] ? 2 this code is not valid Elm, becuase List.head returns Maybe
Maybe type alias Model = { user : Maybe User } view : Model -> Html Msg view model = case model.user of Nothing -> div [] [ text "No user!" ] Just user -> div [] [ text ("Logged in as " ++ user.name) ]
Task A module for async actions that might fail (HTTP). Task errType successType Task String User - if it fails, fail with a String - if it succeeds, succeed with a User
The Elm compiler make sure that 100% of your code is thoroughly checked against corner cases and error cases. This everywhereness becomes a guarantee. And it is only because of this guarantee that Elm programs have virtually no runtime errors. -- Everywhereness as a Foundation, André Staltz
Fourthly, define your view: view : Model -> Html Msg view model = div [] [ button [ onClick Decrement ] [ text "-" ] , div [] [ text (toString model) ] , button [ onClick Increment ] [ text "+" ] ]
Whenever you need to perform some background work, you have to give Elm a command. Elm will go off, perform the command, and call your update function once it's done.
Firstly, define the model: type alias GithubPerson = { name : String , company : String } type alias Model = { username : String , githubPerson : Maybe GithubPerson }
Thirdly, define your update: update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of NewGithubData person -> ( { model | githubPerson = Just person }, Cmd.none ) FetchGithubData -> ( model, fetchGithubData model.username ) ...
Fourthly, define your view: view : Model -> Html Msg view model = case model.githubPerson of Just person -> div [] [ text (person.name ++ ", " ++ person.company) ] Nothing -> div [] [ button [ onClick FetchGithubData ] [ text "Load!" ] ]