Zawiązywanie przyjaźni z językiem Elm

Trochę o mnie

 

  • 2 lata pracy w angularze
  • Rok prowadzenia zespołu
  • Pół roku zainteresowania w językach funkcyjnych

Bartosz Szewczyk

Elm

Strong typed

Virtual-DOM

Html + CSS

Reactive functional

Solid paradigm

Redux?

reFrame?

Elm & Javascript?

Separate runtime!

Static typing

well done

Records!

type alias Model a =
  { id : Int
  , values : List (Int, a)
  , previous : a
  , child : List (Int, a)
  }

No classes?

Algebraic data types

type Action a
  = Create a
  | Update (Int, a)
  | InsertMany List (Int, a)
update : Action a -> Model a -> Model a
update action model =
  case action of
    Create newVal ->
      { model | values = model.values ++ [(model.id, newVal)]
              , id = model.id + 1 }

    Update (id, newVal) ->
      { model | values =
        List.map (update id newVal) model.values }

    InsertMany newValues ->
      { model | values = model.values ++ newValues }

No null/undefined

type Maybe a = Just a | Nothing


doSomethingWithA : Maybe Int -> Int
doSomethingWithA a =
  case a of
    Just i ->
      someAProcessing i
 
    Nothing ->
      someDefaultInt

Compiler that helps

Type inferrence!

Incomplete cases

anonymous records

hermann =
  { first = "Hermann"
  , last = "hesse"
  }

isOver 50 person =
  person.age > 50

answer =
  isOver50 hermann

Compiler that helps

Compiler that helps

  • Finding record keys typos
  • Finding function names typos
  • Detecting Type mismatches
  • Detecting different `if` branches results

Blazing Fast HTML

Only stateless components

view: Signal.Address Action -> Model -> Html
view address model =
  div []
    [ button [ onClick address Decrement ]
             [ text "-" ]
    , div []
          [ text (toString model) ]
    , button [ onClick address Increment ]
             [ text "+" ]
    ]

functional functions

Immutable data structures

two inputs, two outputs

arguments

return

hidden inputs

side-effects

Reactive?

Do you even stream?

bacon.js

kefir.js

RX.js

Enter the signal

Mouse.position : Signal (Int, Int)

Keyboard.presses : Signal Int

Treat like 'array'

filter : (a -> Bool) -> a -> Signal a -> Signal a

onlyNumbers : Signal Int
onlyNumbers = Signal.filter
  (\keyCode -> keyCode >= 48 && keyCode <= 57)
  48 presses 

Treat like 'array'

map : (a -> result) -> Signal a -> Signal result

numbersPressed : Signal Int
numbersPressed =
  Signal.map (\keyCode -> keyCode - 48) onlyNumbers

Treat like 'array'

foldp : (a -> state -> state) -> state -> Signal a -> Signal state

sumPressed : Signal Int
sumPressed =
  Signal.foldp (\n res -> res + n) 0 numbersPressed

Interactive example

How to rule them all?

One architecture

No runtime errors!

Perks

  • Everything is kept in Model
  • Every action is explicit
  • Everything is static typed
  • Everything is modular

Fractal

SuperComponentC.elm

SubComponentA.elm

SubComponentB.elm

C

B

A

view

model

update

view

model

update

Using elm

// embed our Elm program in <div>
var app = Elm.embed(Elm.Stamper,
  document.getElementById('#stamper');

// fullscreen version of Stamper
var app = Elm.fullscreen(Elm.Stamper);

// Stamper with no graphics
var app = Elm.worker(Elm.Stamper);

From JavaScript to Elm

port addUser : Signal (String, UserRecord)

Elm port declaration:

From JavaScript to Elm

app.ports.user.send([
  "Tom",
  { age: 32, job: "lumberjack" }
]);

app.ports.user.send([
  "Sue",
  { age: 37, job: "accountant" }
]);

JS port send:

From Elm to JavaScript

port requestUser : Signal String
port requestUser =
    signalOfUsersWeWantMoreInfoOn

Elm port definiton:

From Elm to JavaScript

app.ports.requestUser.subscribe(databaseLookup);

function databaseLookup(user) {
  var userInfo = database.lookup(user);
  app.ports.user.send(user, userInfo);
}

JS port subscription:

More than enough!

Time travelling debugger

Summary

Pros

  • Static typing for concise codebase
  • Developer friendly compiler
  • Ultra fast virtual dom
  • "Restriction proves helpful"
  • "State is a result of an immutable past"
  • Scalable maintainable architecture
     

  • Fearless refactoring
  • Low learning curve
  • Simple tools

Cons

  • No server-side rendering
  • Elm runtime size (150 KB - 300 KB) 
  • No support for Google Closure Compiler advanced mode
  • No source maps
  • "DOM events can be hard (DnD)"
  • No higher-kinded functions (no generic map)

Thank you very much

Bartosz Szewczyk

@sztobar

"Once you learn Elm (...), getting things done will be more productive, less indirect, less verbose, more organized. All of the JavaScript developers who I met that learned and used Elm so far have been extremely positive about their experience"

André Medeiros

Made with Slides.com