Friendly and functional frontend with Elm



Friendly and functional frontend with Elm

2 0


elm-meetup


On Github tbialecki / elm-meetup

Friendly and functional frontend with Elm

Kamil Durkiewicz, Mateusz Czubak, Tomasz Białecki

ELM

  • Functional Reactive Programming
  • No runtime exceptions
  • Clear syntax
  • Strong / Static Typing
  • Module system and core libraries

Tooling

  • Elm platform = elm-compiler, elm-make, elm-reactor, elm-repl and elm-package
  • own package manager
  • elm-package.json
  • IDE support - Sublime, Atom, WebStorm
npm install -g elm

Syntax - Function declaration

add : Int -> Int -> Int
add x y =
  x + y
add : Int -> Int -> Int
add x y =
  let
    sum = a + b
  in
    sum

Syntax - Type aliases

type alias Description = String

description : Description
description = "abc"
type alias Point = { x : Float, y : Float }

origin : Point
origin =
  { x = 0, y = 0 }

Syntax - Union types

type Fruit = Apple | Banana | Orange

fruitToColor: Fruit -> String
fruitToColor fruit =
  case fruit of
    Apple -> "green"
    Banana -> "yellow"
    Orange -> "orange"

Syntax - Union types

type alias Point = { x : Float, y : Float }

type Shape
  = Circle Point Float
  | Rectangle Point Point

area : Shape -> Float
area shape =
  case shape of
    Circle center radius ->
      pi * radius ^ 2

    Rectangle c1 c2 ->
      abs (c1.x - c2.x) * abs (c1.y - c2.y)

List support

-- Here are four things that are equivalent in elm

numbers : List Int
numbers = [ 1,2,3,4 ]

numbers : List Int
numbers = [ 1..4 ]

numbers : List Int
numbers = 1 :: [ 2,3,4 ]

numbers : List Int
numbers = 1 :: 2 :: 3 :: 4 :: []

List support

length : List a -> Int
length list =
  case list of
    [] ->
        0

    first :: rest ->
        1 + length rest

Banning Nulls

type Maybe a = Nothing | Just a

type alias User =
  { name : String
  , age : Maybe Int
  }

canBuyAlcohol : User -> Bool
canBuyAlcohol user =
  case user.age of
    Nothing ->
      False

    Just age ->
      age >= 18

Automatic function currying

concat : String -> String -> String
concat a b =
  a ++ b

listItem : String -> String
listItem =
  concat "-> "

elm-html

  • blazing fast
  • virtual DOM
  • lazy rendering

elm-html

import Html exposing ( div, text )
import Html.Attributes exposing ( class )

sampleSection : Html
sampleSection =
    div [ class "section" ] [ text "Section 1" ]

Tasks

  • describe async operations
  • may fail or succeed
  • composable

Tasks - composability

getOffers : String -> Task Http.Error (List Offer)
getOffers customerName =
  let
    url = "http://some.api/customer?name="
      ++ customerName
    offersUrl id = "http://some.api/customer/"
      ++ id ++ "/offer"
  in
    Http.get customerDecode url
      `andThen` (\c -> Http.get
        offersDecoder (offersUrl c.id))

Tasks

This code does not send any request:

getSiiliOffice : Task Http.Error String
getSiiliOffice =
  Http.getString
    "http://api.zippopotam.us/pl/50-073"

Commands (Cmd)

  • specifies what effect is needed
  • and how to come back to the application (what messages)

Commmand from task

getSiiliOfficeCmd =
  Task.perform
    SiiliOfficeFailure
    SiiliOfficeSuccess
    getSiiliOffice

To perform the commmand:

main =
  Html.program
    { init = (initialModel, getSiiliOfficeCmd)
    , view = view
    , update = update
    , subscriptions = always Sub.none
    }

Or:

update msg model =
  case msg of
    ...
    GetSiiliOffice ->
      (model, getSiiliOfficeCmd)
    ...

Subscriptions (Sub)

  • for listening for external messages
  • specifies how to prompt the application (what message)

Sub - example

main =
  Html.program
    { init = init
    , view = view
    , update = update
    , subscriptions = always
        (Geolocation.changes CurrentPlace)
    }

Ports

  • for communication with JS code
  • incoming or outcoming

Elm part

port check : String -> Cmd msg

port suggestions :
  (List String -> msg) -> Sub msg

JS part

var app = Elm.Spelling.fullscreen();

app.ports.check.subscribe(function(word) {
    var suggestions = spellCheck(word);
    app.ports.suggestions.send(suggestions);
});

The Elm Architecture

  • Model - the state of your application
  • Update - a way to update your state
  • View - a way to view your state as HTML

The Architecture Skeleton

-- MODEL
type alias Model = { ... }

-- UPDATE
type Msg = Reset | ...

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
  case msg of
  Reset -> ...
...

-- VIEW
view : Model -> Html Msg
view model =
...

Example

elm-zippopotamus

Modularity

The basic idea is: nest The Elm Architecture pattern again and again. Example: Pair of gifs

Questions ?

Friendly and functional frontend with Elm Kamil Durkiewicz, Mateusz Czubak, Tomasz Białecki