Elm

Frontends for Backend developers

I KNOW EVERYTHING ABOUT FILM

 

I HAVE SEEN OVER 240 OF THEM

 

Frontend Development

  • Strong Static Typing
  • Easily Unit testable
  • Low Barrier to Entry
  • No Runtime Exceptions

Elm Development

  • Strong Static Typing
  • Easily Unit testable
  • Low Barrier to Entry
  • No Runtime Exceptions

 

  • Purely Functional
  • Exceptional Compile Errors
  • Faster than Angular and React
  • Enforced Semantic Versioning

Blazing Fast

Why do we like pointers?

  • Pass by reference => less copying => fast
  • Mutability
  • null as a value

Why do we like pointers?

  • Pass by reference => less copying => fast
  • Mutability
  • null as a value

Why don't we like pointers?

  • Think about copy/pass by reference?
  • Harder to reason about code
  • null pointer exceptions

Why do we like pointers?

  • Pass by reference => less copying => fast
  • Mutability
  • null as a value

Why don't we like pointers?

  • Think about copy/pass by reference?
  • Harder to reason about code
  • null pointer exceptions

We like immutability!

  • Always pass by reference
  • Easy to reason about code
  • NO null pointer exceptions
view : Model -> Html Msg
view : Model -> Html Msg

update : Msg -> Model -> Model
update : Msg -> Model -> Model -- original = curried

update : (Msg, Model) -> Model -- uncurried

update : Msg -> (Model -> Model) -- explicitly curried


type alias Model = Int

view : Model -> Html Msg
view model = div [] [text (toString model)]

type alias Model = Int

view : Model -> Html Msg
view model = div [] [text (toString model)]

type Msg = Increment | Decrement

update : Msg -> Model -> Model
update msg model = case msg of
    Increment -> model + 1
    Decrement -> model - 1
elm-make ./src/Buttons1.elm --output=./buttons1.js
==================================== ERRORS ====================================

-- MISSING PATTERNS ----------------------------------------- ./src/Buttons1.elm

This `case` does not have branches for all possibilities.

22|>  case msg of
23|>    Increment -> model + 1

You need to account for the following values:

    Main.Decrement

Add a branch to cover this pattern!

If you are seeing this error for the first time, check out these hints:
<https://github.com/elm-lang/elm-compiler/blob/0.18.0/hints/missing-patterns.md>
The recommendations about wildcard patterns and `Debug.crash` are important!

Detected errors in 1 module.
make: *** [build] Error 1
import Html exposing (beginnerProgram, div, button, text, Html, span)
import Html.Events exposing (onClick)

main =
  beginnerProgram { model = 0, view = view, update = update }

type alias Model = Int

view : Model -> Html Msg
view model =
  div []
    [ button [ onClick Decrement ] [ text "-" ]
    , div [] [text (toString model)]
    , button [ onClick Increment ] [ text "+" ]
    ]

type Msg = Increment | Decrement

update : Msg -> Model -> Model
update msg model =
  case msg of
    Increment -> model + 1
    Decrement -> model - 1
type alias Model = Int

view : Model -> Html Msg
view model =
  div []
    [ button [ onClick Decrement ] [ text "-" ]
    , div [] (List.map viewStar (List.range 0 model))
    , button [ onClick Increment ] [ text "+" ]
    ]

viewStar : Int -> Html Msg
viewStar index = span [style [("color", chooseColor (index % 4))]] [text "*"]

chooseColor : Int -> String
chooseColor c = case c of
  0 -> "red"
  1 -> "yellow"
  2 -> "blue"
  3 -> "green"
  _ -> ""

type Msg = Increment | Decrement

update : Msg -> Model -> Model
update msg model =
  case msg of
    Increment -> model + 1
    Decrement -> model - 1
word : String
word = "TreeBay"

charDict : Dict Int Char
charDict = String.toList word 
    |> List.indexedMap (\index char -> (index, char)) 
    |> Dict.fromList
word : String
word = "TreeBay"

charDict : Dict Int Char
charDict = Dict.fromList 
    (List.indexedMap (\index char -> (index, char)) 
    (String.toList word))

charDict : Dict Int Char
charDict = String.toList word 
    |> List.indexedMap (\index char -> (index, char)) 
    |> Dict.fromList

charDict : Dict Int Char
charDict = Dict.fromList 
    <| List.indexedMap (\index char -> (index, char)) 
    <| String.toList word 
view : Model -> Html Msg
view model =
  div []
    [ button [ onClick Decrement ] [ text "-" ]
    , div [] (List.map viewLetter (List.range 0 model))
    , button [ onClick Increment ] [ text "+" ]
    ]

charDict : Dict Int Char
charDict = String.toList word 
    |> List.indexedMap (\index char -> (index, char)) 
    |> Dict.fromList

viewLetter : Int -> Html Msg
viewLetter index = span [style [("color", chooseColor index)]]
  [text (chooseLetter index)]

chooseLetter : Int -> String
chooseLetter index = case Dict.get (index % String.length word) charDict of
  Nothing -> ""
  (Just letter) -> String.fromChar letter

word : String
word = "TreeBay"

import Navigation
import UrlParser exposing (s, parsePath, top, (<?>), (</>), intParam)

main = Navigation.program (\_ -> Nop)
    { init = init
    , view = view
    , update = update
    , subscriptions = (\_ -> Sub.none)
    }

init : Navigation.Location -> (Model, Cmd Msg)
init location = let l = { location | pathname = "" }
    in case parsePath (top <?> intParam "num") l of
    (Just (Just n)) -> (n, Cmd.none)
    _ -> (0, Cmd.none)
import Navigation

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    Increment -> let newmodel = model + 1 in
      (newmodel, Navigation.modifyUrl <| "?num=" ++ toString newmodel)

    Decrement -> let newmodel = model - 1 in
      (newmodel, Navigation.modifyUrl <| "?num=" ++ toString newmodel)

type alias Model = {
    num       : Int
    , letters : Dict.Dict Int String
    , word    : String
    , size    : Int
}

newModel : Int -> String -> Model
newModel num word = Model num (newCharDict word) word (String.length word)

newCharDict : String -> Dict.Dict Int String
newCharDict word = Dict.fromList 
    <| List.indexedMap (\index char -> (index, String.fromChar char)) 
    <| String.toList word
import Navigation
import UrlParser 
    exposing (s, parsePath, top, (<?>), (</>), intParam, stringParam, map, Parser)

init : Navigation.Location -> (Model, Cmd Msg)
init location = 
    let loc = { location | pathname = "" } -- we parse the arguments not the path
    in case parsePath urlpath loc of
    (Just model) -> (model, Cmd.none)
    _ -> (newModel 0 "", Cmd.none)

parseModel : Maybe Int -> Maybe String -> Model
parseModel maybeNum maybeStr = 
    let num = Maybe.withDefault 0 maybeNum
        word = Maybe.withDefault "" maybeStr
    in newModel num word

urlSpec : Parser (Maybe Int -> Maybe String -> b) b
urlSpec = top <?> intParam "num" <?> stringParam "word"

urlpath : Parser (Model -> Model) Model
urlpath = UrlParser.map parseModel urlSpec
UrlParser.map : a -> Parser a b -> Parser (b -> c) c

UrlParser.parsePath : Parser (b -> c) c -> Location -> Maybe c

a : Maybe Int -> Maybe String -> Model
b : Model
c : Model
type Msg = Increment 
  | Decrement
  | EditWord String

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    Increment -> let newmodel = {
        model | num = model.num + 1
    } in (newmodel, seturl newmodel)

    Decrement -> let newmodel = {
        model | num = model.num - 1
    } in (newmodel, seturl newmodel)

    (EditWord w) -> let 
        newmodel = newModel model.num w
    in (newmodel, seturl newmodel)

seturl : Model -> Cmd Msg
seturl {num, word} = Navigation.modifyUrl <| "?num=" ++ toString num ++ "&word=" ++ word
view : Model -> Html Msg
view model =
  div []
    [ button [ onClick Decrement ] [ text "-" ]
    , div [] (List.map (viewLetter model) (List.range 0 model.num))
    , button [ onClick Increment ] [ text "+" ]
    , viewInput "Word" model.word 
    ]

viewInput : String -> String -> Html Msg
viewInput name v = div [] [
        label [] [text name]
        , input [
            Html.Attributes.type_ "text"
            , onWithOptions "input" preventDefaults (Json.map EditWord targetValue)
            , value v
        ] []
    ]
suite : Test
suite = describe "choose letter" [
        test "letter" <| \_ -> Expect.equal (chooseLetter (newModel "TreeBay") 5) "a"
        , test "wrap" <| \_ -> Expect.equal (chooseLetter (newModel "TreeBay") 11) "B"
        , test "empty" <| \_ -> Expect.equal (chooseLetter (newModel "") 3) ""
    ]
$ elm-test
Success! Compiled 0 modules.
Successfully generated /dev/null
Success! Compiled 1 module.
Successfully generated 
    ~/elm-example/elm-stuff/generated-code/elm-community/elm-test/elmTestOutput.js

elm-test 0.18.12
----------------

Running 3 tests. To reproduce these results, run: elm-test --fuzz 100 --seed 186127600


TEST RUN PASSED

Duration: 227 ms
Passed:   3
Failed:   0
suite : Test
suite = describe "choose letter" [
        fuzz string "fuzz 5" <| 
            \randString -> Expect.equal 
                (testChooseLetter randString 5) 
                (chooseLetter (newModel randString) 5)
    ]
testChooseLetter : String -> Int -> String
testChooseLetter word index = if String.length word == 0 then ""
     else let chars = Array.fromList <| String.toList word
          in case Array.get (index % String.length word) chars of
                Nothing -> ""
                (Just j) -> String.fromChar j
suite : Test
suite = describe "choose letter" [
        fuzz string "fuzz 5" <| 
            \randomlyGeneratedString -> Expect.equal 
                (testChooseLetter randomlyGeneratedString 5) 
                (chooseLetter (newModel randomlyGeneratedString) 5)
    ]
suite : Test
suite = describe "choose letter" [
        fuzz2 string int "fuzzy" <| 
            \randString randIndex -> Expect.equal 
                (testChooseLetter randString randIndex) 
                (chooseLetter (newModel randString) randIndex)
    ]
testChooseLetter : String -> Int -> String
testChooseLetter word index = if String.length word == 0 then ""
     else let chars = Array.fromList <| String.toList word
          in case Array.get (index % String.length word) chars of
                Nothing -> ""
                (Just j) -> String.fromChar j

Low Barrier to Entry

Elm Development

  • Strong Static Typing
  • Easily Unit testable
  • Low Barrier to Entry
  • No Runtime Exceptions

 

  • Purely Functional
  • Exceptional Compile Errors
  • Faster than Angular and React
  • Enforced Semantic Versioning

Everything you like about backend development and more, now available in the Frontend.

Contact:

waschulze@ebay.com

awalterschulze@gmail.com

#ecg-pure

Elm frontends for backend developers

By Walter Schulze

Elm frontends for backend developers

  • 176

More from Walter Schulze