Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction into Elm

Introduction into Elm

Introduction into Elm

Elm is a functional programming language that compiles into Javascript. It is well suited for interactive web applications written in a functional and declarative way. It enables you to write more robust applications through its static types without runtime errors.

Martin will give an introduction into Elm and a walk through on how to structure an application in accordance to The Elm Architecture.

Video:https://youtu.be/1iObbiyvCJg

=====================================================
Follow us and join our Slack community:

- ReactJS Norway's site: http://bit.ly/2ka4hC8
- Facebook: http://bit.ly/2kxmHxW
- Instagram: http://bit.ly/2kpysnJ
- Twitter: http://bit.ly/2kaehvl
- Youtube: http://bit.ly/2kANuJl
- Slack Community: https://goo.gl/YwUUKJ

ReactJS Norway

March 09, 2017
Tweet

More Decks by ReactJS Norway

Other Decks in Programming

Transcript

  1. function add(a, b) { 
 return a + b; 


    } 
 
 
 add(2, 1); // 3 
 
 Function name add a b = a + b 
 
 
 add 2 1 -- 3 
 
 Arguments JS Elm Implicit return add : Int -> Int -> Int Return type
  2. headerView task = 
 header 
 [ class "header" ]

    
 [ h1 [] [ text "todos" ] 
 , input 
 [ class "new-todo" 
 , placeholder "What needs to be done?" 
 , autofocus True 
 , value task 
 , name "newTodo" 
 , onInput UpdateField 
 , onEnter Add 
 ] 
 [] 
 ] 
 

  3. headerView task = 
 header 
 [ class "header" ]

    
 [ h1 [] [ text "todos" ] 
 , input 
 [ class "new-todo" 
 , placeholder "What needs to be done?" 
 , autofocus True 
 , value task 
 , name "newTodo" 
 , onInput UpdateField 
 , onEnter Add 
 ] 
 [] 
 ] 
 

  4. headerView task = 
 header 
 [ class "header" ]

    
 [ h1 [] [ text "todos" ] 
 , input 
 [ class "new-todo" 
 , placeholder "What needs to be done?" 
 , autofocus True 
 , value task 
 , name "newTodo" 
 , onInput UpdateField 
 , onEnter Add 
 ] 
 [] 
 ] 
 

  5. function add(a, b) { 
 window.add = undefined; 
 return

    a + b; 
 } Side-effects add(2, 1); // 3 add(2, 1);
  6. point = { x = 3, y = 4 }

    
 
 
 updatePoint point = 
 { point | x = 5 } -- { x = 5, y = 4 } 
 
 Record type
  7. point = { x = 3, y = 4 }

    
 
 
 updatePoint point = 
 { point | x = 5 } -- { x = 5, y = 4 } 
 

  8. point : { x : Int, y : Int }

    point = { x = 3, y = 4 } 
 
 
 updatePoint : { x : Int, y : Int } -> { x : Int, y : Int } 
 updatePoint point = 
 { point | x = 5 } Type signature for a point
  9. updatePoint : { x : Int, y : Int }

    -> { x : Int, y : Int } 
 updatePoint point = 
 { point | x = 5 } updatePoint : Point -> Point 
 updatePoint point = 
 { point | x = 5 } 
 
 
 point : { x : Int, y : Int } point = { x = 3, y = 4 } 
 
 
 type alias Point = 
 { x : Int, y : Int } point : Point point = { x = 3, y = 4 } 

  10. listView tasks = 
 ul [] (List.nap taskView tasks) 


    
 
 
 taskView task = 
 li [] [ text task.name ] 

  11. -- NAMING ERROR ------------------------------------------------------ error.elm Cannot find variable `List.nap`. 17|

    ul [] (List.nap taskView tasks) ^^^^^^^^ `List` does not expose `nap`. Maybe you want one of the following? List.map List.any List.map2 List.map3
  12. 
 
 main = 
 listView [ { name =

    0 } ] listView tasks = 
 ul [] (List.map taskView tasks) 
 
 
 
 taskView task = 
 li [] [ text task.name ] 

  13. -- TYPE MISMATCH ----------------------------------------------------- error.elm The argument to function `listView`

    is causing a mismatch. 20| listView [ { name = 0 } ] ^^^^^^^^^^^^^^^^ Function `listView` is expecting the argument to be: List { name : String } But it is: List { name : number } Hint: Problem in the `name` field. I always figure out field types in alphabetical order. If a field seems fine, I assume it is "correct" in subsequent checks. So the problem may actually be a weird interaction with previous fields.
  14. type CompassPoint 
 = North 
 | South 
 |

    East 
 | West 
 
 Union types type User 
 = Anonymous 
 | Named String 

  15. type Maybe a 
 = Just a 
 | Nothing

    
 
 Generic type Maybe
  16. type alias Task = 
 { name : String 


    , description : Maybe String 
 } 
 
 Can either have an description or nothing descriptionView : Task -> String 
 descriptionView task = 
 case task.description of 
 Just description -> 
 description
  17. -- MISSING PATTERNS -------------------------------------------------- error.elm This `case` does not have

    branches for all possibilities. 12|> case task.description of 13|> Just description -> 14|> description You need to account for the following values: Maybe.Nothing Add a branch to cover this pattern!
  18. type alias Task = 
 { name : String 


    , description : Maybe String 
 } 
 
 descriptionView : Task -> String 
 descriptionView task = 
 case task.description of 
 Just description -> 
 description 
 Nothing -> 
 “No description” 

  19. Model Update View Message + state = new state Application

    state View for current state Message
  20. type alias Model = 
 { count : Int 


    } 
 type Msg 
 = Increment 
 | Decrement update : Msg -> Model -> Model 
 update msg model = 
 case msg of 
 Increment -> 
 { model | count = model.count + 1 } 
 
 Decrement -> 
 { model | count = model.count - 1 } view : Model -> Html Msg 
 view model = 
 div [ class "counter" ] 
 [ button [ onClick Decrement ] [ text "-" ] 
 , text (toString model.count) 
 , button [ onClick Increment ] [ text "+" ] 
 ] 

  21. type AddTodo = { type: "ADD_TODO", id: number, title: string

    }; 
 type ToggleTodo = { type: "TOGGLE_TODO", id: number }; function todos(state: State, action: Action): State { 
 switch (action.type) { 
 case "ADD_TOOD": 
 ... 
 case "TOGGLE_TODO": 
 ... 
 } 
 } type Action = AddTodo | ToggleTodo; 
 Typo Typed Redux
  22. ERROR in ./stores/todos.ts (12,12): error TS2678: Type '"ADD_TOOD"' is not

    comparable to type '"ADD_TODO" | "TOGGLE_TODO"'.
  23. type AddTodo = { type: "ADD_TODO", id: number, title: string

    }; 
 type ToggleTodo = { type: "TOGGLE_TODO", id: number }; 
 
 type Action = AddTodo | ToggleTodo; 
 
 function todos(state: State, action: Action): State { 
 switch (action.type) { 
 case "ADD_TODO": 
 ... 
 case "TOGGLE_TODO": 
 ... 
 } 
 } 
 
 Typed Redux
  24. type AddTodo = { type: "ADD_TODO", id: number, title: string

    }; 
 type ToggleTodo = { type: "TOGGLE_TODO", id: number }; type ShowCompleted = { type: "SHOW_COMPLETED" }; 
 type Action = AddTodo | ToggleTodo; 
 
 function todos(state: State, action: Action): State { 
 switch (action.type) { 
 case "ADD_TODO": 
 ... 
 case "TOGGLE_TODO": 
 ... 
 } 
 } 
 Typed Redux
  25. type AddTodo = { type: "ADD_TODO", id: number, title: string

    }; 
 type ToggleTodo = { type: "TOGGLE_TODO", id: number }; type ShowCompleted = { type: “SHOW_COMPLETED" }; 
 type Action = AddTodo | ToggleTodo | ShowCompleted; 
 
 function todos(state: State, action: Action): State { 
 switch (action.type) { 
 case "ADD_TODO": 
 ... 
 case "TOGGLE_TODO": 
 ... 
 } 
 } 
 Typed Redux
  26. ERROR in ./stores/todos.ts (11,61): error TS2366: Function lacks ending return

    statement and return type does not include 'undefined'.
  27. -- MISSING PATTERNS -------------------------------------------------- error.elm This `case` does not have

    branches for all possibilities. 16|> case msg of 17|> AddTodo -> 18|> model 19|> 20|> ToggleTodo -> 21|> model You need to account for the following values: Main.ShowCompleted Add a branch to cover this pattern!