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

Building Web Apps in Elm

Building Web Apps in Elm

As developers, we have been building rich web-based applications (or trying to) for some time and still can't avoid the complexity behind modeling the state of the world around us. In this talk we'll discuss a functional approach that radically simplify things using reactive web components backed by Elm, a functional reactive language that compiles to HTML, CSS and JavaScript. We choose Elm to bring us simplicity from FP principles and ultimately to bring its powerful type system to JavaScript on the browser.

Jivago Alves

July 03, 2015
Tweet

Other Decks in Technology

Transcript

  1. $ whoami - Developer @ Stack Builders - Software consulting

    agency specializing in Haskell and Ruby development - I'm from Brazil but I don't know how to dance samba… :)
  2. Agenda - Rich Web-Based Apps - Elm (syntax, types) -

    Elm Architecture - Communicating with Mailboxes - Consuming APIs with Tasks
  3. Rich Web-Based Apps A simple checkout page with - list

    of products - quantity picker - buy button
  4. Rich Web-Based Apps A simple checkout page until we -

    introduce complexity (price, discount, fees) - have to model state (store selected product) - (summary = current price * quantity + fee - discount) - need to handle changes over time - have to update (parts of) the UI
  5. We'd like to - change our app without fear of

    breaking it - ensure our reasoning (always) makes sense - have simplicity for the UI - tell what to render instead of how
  6. Elm - FRP language - functions and immutability - asynchronous

    dataflow (reactive) - compiles to JS, CSS, Html (elm-html) - virtual dom for fast DOM updates - declarative approach to UI design - statically typed (ADTs)
  7. Syntax Literals 3 : number 3.17 : Float "Hello" :

    String 'a' : Char True : Bool [1, 2, 3] : List number Comments -- single line comment {- multiline comment -}
  8. Syntax Records > p = { x = 3, y

    = 4 } { x = 3, y = 4 } > p.x 3 > { p | x <- 5 } { x = 5, y = 4 } -- new record Extensible Records > { p - x } { y = 4 } > { p | z = 5 } { x = 3, y = 4, z = 5 }
  9. Functions > \x y -> x + y > db

    x = x + x > sq x = x * x > List.map sq [1,2,3] [1, 4, 9] > List.map (sq >> db) [1,2,3] [2, 8, 18]
  10. Types - contracts ensured by compiler db : Int ->

    Int db x = x + x - expressive types for modeling your app type Status = Unstarted | Started | Finished type User = Anonymous | LoggedIn String type Maybe a = Just a | Nothing
  11. $ elm-package $ elm-package install -y Downloading elm-lang/core Downloading evancz/elm-html

    Downloading evancz/elm-http Downloading evancz/virtual-dom Packages configured successfully!
  12. $ elm-package $ elm-package diff Dandandan/parser 5.0.4 5.1.0 Comparing Dandandan/parser

    5.0.4 to 5.1.0... This is a MINOR change. ------ Changes to module Parser.Char - MINOR ------ Added: quoted : Parser result -> Parser result
  13. $ elm-make $ elm-make HN.elm --yes --output elm.js Downloading elm-lang/core

    Downloading evancz/elm-html ... Packages configured successfully! Compiled 39 files Successfully generated elm.js
  14. $ elm-repl $ elm-repl > List.map ((*) 2) [1..10] [2,4,6,8,10,12,14,16,18,20]

    : List number > import MyCSV > MyCSV.isValid "First, Second\n" True : Bool
  15. Reacting to Signals - mapping to a new signal -

    Signal.map not Mouse.isDown - folding from the past - Signal.foldp (\click total -> total + 1) 0 Mouse.clicks - merging signals - Signal.merge menuActions buttonActions - filtering signals - Signal.filter isEven 0 numbers
  16. Elm Architecture - Model type alias Story = { id

    : Int , by : String , score : Int , time : Int , title : String , read : Bool }
  17. Elm Architecture - Model type alias Story = { id

    : Int , by : String , score : Int , time : Int , title : String , read : Bool } type alias AppState = { stories : List Story }
  18. Elm Architecture - View view : AppState -> Html view

    appState = ul [ id "app" ] (List.map viewStory appState.stories) viewStory : Story -> Html viewStory s = li [ class "story" ] [ text s.title ]
  19. Elm Architecture - Update type Action = NoOp | MarkAsRead

    Int update : Action -> AppState -> AppState update action app = case action of NoOp -> app MarkAsRead id -> …
  20. On click we... - want to mark as read -

    want to decouple from the update logic - don't care about how to update - pub / sub based logic
  21. Mailboxes - communication hub type alias Mailbox a = {

    address : Address a -- we can send messages to , signal : Signal a -- signal of msg we react to }
  22. Mailboxes viewStory : Address Action -> Story -> Html viewStory

    addr s = div [ onClick addr (MarkAsRead s.id) ] [ if s.read then text s.title else strong [ ] [ text s.title ] ]
  23. Mailboxes - compared with pub/sub in JS - types make

    the protocol explicit - compiler ensures the "right" protocol
  24. Consuming APIs - make requests - decode the response into

    our internal types - we don't want to allow invalid state - handle errors - give feedback when something is wrong
  25. Chaining Tasks fetchStory `andThen` emitNewStory emitNewStory : Story -> Task

    Http.Error () emitNewStory s = Signal.send actionsMailbox.address (NewStory s)
  26. Handling Task Errors fetchStory `andThen` emitNewStory `onError` emitApiError emitApiError :

    Http.Error -> Task Http.Error () emitApiError err = Signal.send actionsMailbox.address ApiError
  27. Decoders - turn input into internal types - no invalid

    state inside of our app fetchStory : Task Http.Error Story fetchStory = Http.get storyDecoder storyUrl
  28. Decoders storyDecoder : Json.Decoder Story storyDecoder = Story `map` ("id"

    := int) `apply` ("by" := string) `apply` ("score" := int) `apply` ("time" := int) `apply` ("title" := string) `apply` ("read" := bool)
  29. Packages - Parser library (no regexs!) - Dandandan/parser at http://git.io/vtu98

    - Example of CSV parser at http://git.io/vtu9i - Undo / Redo - TheSeamau5/elm-undo-redo http://git.io/vtuHd - Property-based testing - TheSeamau5/elm-check at http://git.io/vtuQY
  30. References - Elm Docs http://elm-lang.org/docs - Elm Concurrent FRP http://goo.gl/CHA0XC

    - Lot of good examples on - http://elm-lang.org/examples