Slay
Internet Explorer

SERVER

Is the browser IE?

Request

YES

REJECT THE REQUEST

SERVE NORMAL CONTENT

NO

app.get("/", (req, res) => {
  if(isUsingIE(req)) {
    res.status(400)
       .send("Use a true browser!")
  } else { res.render("index.ejs"); }
});



app.get("/", (req, res) => {
  if(isUsingIE(req)) {
    res.status(400)
       .send("Use a true browser!")
  } else { res.render("index.ejs"); }
});



app.get("/haskell", (req, res) => {
  if(isUsingIE(req)) {
    res.status(400)
       .send("Use a true browser!")
  } else { res.render("haskell.ejs"); }
});

/haskell

/

Welcome to my amazing website!

Haskell is amazing!

USER CODE

USER CODE

/haskell

/

Welcome to my amazing website!

Haskell is amazing!

USER CODE

USER CODE

FRAMEWORK

/haskell

/

Welcome to my amazing website!

Haskell is amazing!

USER CODE

USER CODE

FRAMEWORK

USER CODE

MIDDLEWARE

/haskell

/

Welcome to my amazing website!

Haskell is amazing!

USER CODE

USER CODE

FRAMEWORK

USER CODE

MIDDLEWARE

REJECT THE REQUEST

/haskell

/

Welcome to my amazing website!

Haskell is amazing!

USER CODE

USER CODE

FRAMEWORK

USER CODE

MIDDLEWARE

REJECT THE REQUEST

SERVER

Is the browser IE?

Request

YES

REJECT THE REQUEST

SERVE NORMAL CONTENT

NO

/haskell

/

Welcome to my amazing website!

Haskell is amazing!

USER CODE

USER CODE

FRAMEWORK

USER CODE

MIDDLEWARE

REJECT THE REQUEST

/haskell

/

Welcome to my amazing website!

Haskell is amazing!

USER CODE

USER CODE

REJECT THE REQUEST

USER CODE

If the browser is IE

Is the browser IE?

Request

YES

REJECT THE REQUEST

NO

Is there an \(\texttt{auth}\) cookie?

NO

LOGIN PAGE

Is the browser IE?

Request

YES

REJECT THE REQUEST

NO

Is there an \(\texttt{auth}\) cookie?

NO

LOGIN PAGE

YES: User

 

 

ROUTER

 

 

 

Just Home

/

Just Haskell

/haskell

POST /haskell

referer: lambda.org

 

{ "message": "hello",

  "dest": "Evan" }

Just ( SendMessage

   { to = "Evan"

   , content = "Hello"

   , sentFrom ="lambda.org"

   } )

Nothing

Is the browser IE?

Request

YES

REJECT THE REQUEST

NO

Is there an \(\texttt{auth}\) cookie?

NO

LOGIN PAGE

YES: User

 

 

ROUTER

 

 

 

Just Home

/

Just Haskell

/haskell

POST /haskell

referer: lambda.org

 

{ "message": "hello",

  "dest": "Evan" }

Just ( SendMessage

   { to = "Evan"

   , content = "Hello"

   , sentFrom ="lambda.org"

   } )

Nothing

serveStatic "Welcome!"

serveStatic "Haskell!"

send { to = "Evan", from = User

          , content = "Hello" };

log "Message sent from: lambda.org"

notFound

Server:

\(\texttt{Request} \to \texttt{Response}\)

Server:

\(\texttt{Request} \to \texttt{IO Response}\)

Elm, a functional language?

Sébastien Besnier

@_sebbes_

What is elm?

Programming language
designed for front end development

17k LoC

200k LoC

A language with no runtime exception

 

  • total functions
  • immutable data
  • strong typing

And a Lot More!

Some cool libs

WebGL support

3D Physics Engine

What about performance?

Real World App

  • Signup/Signin
  • Content creation
  • Routing

694

Is it hard to achieve?

elm

init

reactor

install

make

publish

repl

 

a tiny dev server

add new dependencies

download deps, compile, build really quickly

packages

 

 

Testimonials

We have newcomers go through the official Elm guide, we sit down with them to answer questions and do concrete work, and after a couple of weeks, we don’t get requests for help anymore.

 

https://www.humio.com/whats-new/blog/why-we-chose-elm-for-humio-s-web-ui

We have newcomers go through the official Elm guide, we sit down with them to answer questions and do concrete work, and after a couple of weeks, we don’t get requests for help anymore.

 

https://www.humio.com/whats-new/blog/why-we-chose-elm-for-humio-s-web-ui

A beginner Elm developer, in our experience, can be productive in a couple of weeks and can master the language in a couple of months.

https://dev.to/lucamug/elm-6m8

Testimonials

We have newcomers go through the official Elm guide, we sit down with them to answer questions and do concrete work, and after a couple of weeks, we don’t get requests for help anymore.

 

https://www.humio.com/whats-new/blog/why-we-chose-elm-for-humio-s-web-ui

A beginner Elm developer, in our experience, can be productive in a couple of weeks and can master the language in a couple of months.

https://dev.to/lucamug/elm-6m8

Several rounds of summer interns have also proven that it is possible to learn Elm and our systems, and become productive in a matter of days.

 

https://blogg.bekk.no/using-elm-at-vy-e028b11179eb

Testimonials

Amazing compiler error messages

REPL demo!

Rendering HTML

text : String -> Html



node :
  String 
  -> List Attributes
  -> List Html
  -> Html
node tag attributes children =
  ...

TWO BUILDING BLOCKS

node "p" [class "btn"] [ text "hello"]
<p class="btn">Hello</p>
text : String -> Html

node :
  String 
  -> List Attributes
  -> List Html
  -> Html
node tag attributes children =
  ...

p = node "p"
ul = node "ul"
div = node "div"
...
p [class "btn"] [ text "hello"]
<p class="btn">Hello</p>
viewKids kids =
  ul [] 
    (List.map
      (\kid -> li [] [ text kid ])
      kids
    )

Displaying Lists

 

It's just a map!

Hey, I'm used to write HTML, what about some "templating" language?

Hey, I'm used to write HTML, what about some "templating" language?

Templating language demands:

  • defining & learning new syntax
     
  • reinventing conditionals, loops, "context", "inheritance", "functions"
     
  • building tools (coloration, completion, ...)
     
  • bridging types from "host" language
    (hi Ivy!)
     
  • deciding where the code should live

Hey, I'm used to write HTML, what about some "templating" language?

Templating language demands:

  • defining & learning new syntax
     
  • reinventing conditionals, loops, "context", "inheritance", "functions"
     
  • building tools (coloration, completion, ...)
     
  • bridging types from "host" language
    (hi Ivy!)
     
  • deciding where the code should live

Free/useless if you directly use your language with text and node!

Rendering HTML

What about CSS?

External CSS

<html><head>
  <link href="/my-style.css">
  <script src="main.js"></script>
</head>
<body>
  <div id="myapp"></div>
  <script>
  var app = Elm.Main.init({
    node: document.getElementById('myapp')
  });
  </script>
</body></html>

External CSS

<html><head>
  <link href="/my-style.css">
  <script src="main.js"></script>
</head>
<body>
  <div id="myapp"></div>
  <script>
  var app = Elm.Main.init({
    node: document.getElementById('myapp')
  });
  </script>
</body></html>
-- Main.elm

p [ class "my-btn"
  , style "color" "red"
  ]
  [ text "hello"]

Some Issues when dealing with External CSS:

  • is CSS valid?
  • is it correctly loaded?
  • CSS code maintenance & refactor

 

elm-css

Some Issues when dealing with External CSS:

  • is CSS valid?
  • is it correctly loaded?
  • CSS code maintenance & refactor

Let's use our existing compiler tackle all of that!

elm-css

elm-css

-- Main.elm
div []
 [ p [ css 
       [ backgroundColor (rgb 255 0 255)
       , padding (px 30) ] 
     ]
     [ text "hello" ]
 ]

elm-css

<div>
  <style>._72f9689 {
    background-color:rgb(255, 0, 255);
    padding:30px;
  }
  </style>
  <p class="_72f9689">hello</p>
</div>
-- Main.elm
div []
 [ p [ css 
       [ backgroundColor (rgb 255 0 255)
       , padding (px 30) ] 
     ]
     [ text "hello" ]
 ]

elm-css

-- Main.elm
div []
 [ p [ buttonStyle ] [ text "hello" ]
 , p [ buttonStyle ] [ text "good bye" ]
 ]

buttonStyle = 
  css 
    [ backgroundColor (rgb 255 0 255)
    , padding (px 30)
    ] 

Some Issues when dealing with External CSS:

  • is CSS valid?
  • is it correctly loaded?
  • CSS code maintenance & refactor

Let's use our existing compiler tackle all of that!

elm-css

Organize the style as normal code!

elm-ui

Some Issues when dealing with CSS:

  • Yet Another Complex Language to learn
  • Context sensitive
  • How to vertically center an element?

 

elm-ui

Some Issues when dealing with CSS:

  • Yet Another Complex Language to learn
  • Context sensitive
  • How to vertically center an element?

 

elm-ui

  • "If it compiles, it works" applied to the layout
  • no "cascading"
  • simple primitives

elm-ui

Building blocks

text : String -> Element

row : List Attribute
      -> List Element
      -> Element
      
column : List Attribute
      -> List Element
      -> Element


layout : List Attribute
         -> List Element
         -> Html

elm-ui

Building blocks

text : String -> Element

row : List Attribute
      -> List Element
      -> Element
      
column : List Attribute
      -> List Element
      -> Element


layout : List Attribute 
         -> List Element
         -> Html
button :
  List Attribute
  -> 
  { onPress : Msg
  , label : Element
  }
  -> Element

elm-ui

Example

row [ centerY, centerX, width fill ]
  [ text "Home"
  , el [ centerX ] (text "Lambda Lille")
  , el [ alignRight ] (text "Connexion")
  ]

Text

Lambda Lille

Connexion

Home

Side Note: Records

type alias Person =
  { name : String
  , age: Int
  }
  
view : Person -> Html
view p =
  text p.name
  

-- FUNCTION CALL:
view { name = "Seb", age = 42 }

Side Note: Records

List.map .age 
   [{ name = "Seb", age = 42 }
   ,{ name = "Bob", age = 53 } ]

-- RESULT:
[ 42, 53 ]


-- SIGNATURE:
.age : { anyRecord | age : value } -> value

elm-ui

Responsiveness

Displaying depends on screen size.

elm-ui

Responsiveness

view model =
  case model.screenWidth of
    Phone -> viewPhone model.page
    Tablet -> viewTable model.page
    Desktop -> viewDesktop model.page
    BigDesktop -> viewBigDesktop model.page

Displaying depends on screen size.

Let's make that explicit!

What's a pure functional programming language?

What's a pure functional programming language?

Side effects are totally "controlled"

What's a pure functional programming language?

Side effects are totally "controlled"

What's a pure functional programming language?

Side effects are totally "controlled"

What's a pure functional programming language?

Side effects are totally "controlled"

IO

What's a pure functional programming language?

Side effects are totally "controlled"

IO

List.head []
Binding to C (it is even "easy")

What's a pure functional programming language?

Side effects are totally "controlled"

IO

List.head []
Binding to C (it is even "easy")

init : Model

view : Model -> Html Msg

update : Msg -> Model -> Model
init : Model

view : Model -> Html Msg

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

Commands (Cmd) are "requests" to (e.g):

  • HTTP
activateCmd : Cmd Msg
activateCmd = post 
  { url = "/activate"
  , expect =
     expectWhatever GotActivationResult
  , body = emptyBody
  }

Commands (Cmd) are "requests" to (e.g):

  • HTTP
activateCmd : Cmd Msg
activateCmd = post 
  { url = "/activate"
  , expect =
     expectWhatever GotActivationResult
  , body = emptyBody
  }

Msg generated when response received

type Msg
  = ButtonClicked
  | GotActivationResult (Result Error ())
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    ButtonClicked ->
      (model, activateCmd)
    
    GotActivationResult (Ok ()) ->
      ({model | message = "Activated!"}
      , Cmd.none
      )
   
    GotActivationResult (Err _) ->
      ({model | message = "Error :/"}
      , Cmd.none
      )

Commands (Cmd) are "requests" to (e.g):

  • HTTP
  • Time
Time.now : (Posix -> msg) -> Cmd msg
Time.here : (Zone -> msg) -> Cmd msg

Commands (Cmd) are "requests" to (e.g):

  • HTTP
  • Time
  • Randomness

Commands (Cmd) are "requests" to (e.g):

  • HTTP
  • Time
  • Randomness
  • JS
port copyToClipboard : String -> Cmd msg
update msg model =
  case msg of
    CopyButtonClicked ->
      ( model
      , copyToClipboard "Lorem Ipsum"
      )
const app = Elm.Main.init({
  node: document.getElementById('root'),  
});

app.ports.copyToClipboard.subscribe(
  content =>
  	navigator.clipboard.writeText(content)
);
index.js

Cmd

Elm Ports

Cmd

Sub

Elm Ports

It's just message exchange!

Microphone Volume

Continuously send volume

Microphone Volume

Ports?

Continuously send volume

Microphone Volume

Ports?

Please, start sending volume

Please, stop sending volume

Custom Element!

Custom Element!

function createMicListener(
  callback: (volume: number) => void
): { disconnect: () => void }
{ /*...*/}
    

index.js

Custom Element!

function createMicListener(
  callback: (volume: number) => void
): { disconnect: () => void }{ /*...*/}
    
customElements.define("audio-meter",
  class extends HTMLElement {
    connectedCallback() {
      this.micListener = createMicListener((volume)=>{
        this.dispatchEvent(new CustomEvent(
          "volume",{"detail": volume}
        ));
      });
    }
    disconnectedCallback() {
      this.micListener.disconnect();
    }
  }
);
index.js

Custom Element!

import Json.Decode as D

view model =
  if model.isRecording then
    div [] 
      [ node "audio-meter"
         [ on "volume" 
    	    (D.field "detail" (D.map GotVolume float))
         ]
      , text ("Volume:"++ Str.fromFloat model.volume)
      ]
      []
  else
    text "Not listening"
    
update msg model =
  case msg of
    GotVolume volume ->
      { model | volume = volume }

Custom Element!

Custom Elements for:

  • Tiny widgets to get some atomic data (like microphone volume)
  • Audio/Video player
  • Integrate components from other framework (e.g. Google Maps)

What's a pure functional programming language?

Side effects are totally "controlled"

IO

List.head []
Binding to C (it is even "easy")

Elm Architecture

Ports for FFI

What's a pure functional programming language?

Side effects are totally "controlled"

IO

Elm Architecture

Ports for FFI

Custom Elements

-- run arbitrary code with HTML type

List.head []
Binding to C (it is even "easy")

JSON to Elm

Decode them all!

{
  "name": "Super Camp",
  "duration": 7.0,
  "kids": ["Sébastien", "Thomas"]  
}

JSON

import Json.Decode as D

type alias Camp =
  { name : String
  , kids : List String
  , duration : Float
  }

campDecoder : D.Decoder Camp
campDecoder =
  D.map3 Camp
    (D.field "name" D.string)
    (D.field "kids" (D.list D.string))
    (D.field "duration" D.float)
import Simple.JSON as JSON


type Camp =
  { name : String
  , kids : List String
  , duration : Float
  }

main = do
  case JSON.readJSON theJSON of
    Right (camp :: Camp) -> do
      -- Do stuff with camp!
    Left e -> do
      -- Handle failre
{
  "name": "Super Camp",
  "duration": 7.0,
  "kids": ["Sébastien", "Thomas"]  
}

JSON

{
  "name": "Super Camp",
  "duration": 7.0,
  "children": ["Sébastien", "Thomas"]
}

JSON

Multiple options:

  • Change \(\texttt{kids}\) to \(\texttt{children}\) in the entire code base

  • Write a new \(\texttt{CampJson}\) type and a \(\texttt{CampJson} \to \texttt{Camp}\)

  • Write a custom decoder
import Json.Decode as D

type alias Camp =
  { name : String
  , kids : List String
  , duration : Float
  }

campDecoder : D.Decoder Camp
campDecoder =
  D.map3 Camp
    (D.field "name" D.string)
    (D.field "children" (D.list D.string))
    (D.field "duration" D.float)
import Json.Decode as D

type alias Camp =
  { name : String
  , kids : List String
  , duration : Float
  }

campDecoder : D.Decoder Camp
campDecoder =
  D.map3 Camp
    (D.field "name" D.string)
    (D.field "children" (D.list D.string))
    (D.field "duration" D.float)

Decoders define Explicit Boundaries with the Outside

{
  "name": "Super Camp",
  "duration": 7.0,
  "children": ["Sébastien", "Thomas"]
}

JSON

{ "metadata": {
    "name": "Super Camp",
    "place": "Paris"  
  }, 
  "duration": 7.0,
  "children": [
    { "name": "Sébastien", "age": 42},
    { "name": "Thomas", "age": 42}
  ]
}

JSON

import Json.Decode as D

type alias Camp =
  { name : String
  , kids : List String
  , duration : Float
  }

campDecoder : D.Decoder Camp
campDecoder =
  D.map3 Camp
    (D.at [ "metadata", "name" ] D.string)
    (D.field "children" (D.list
    	(D.field "name" D.string)
    ))   
    (D.field "duration" D.float)
succeed : a -> Decoder a

field : String -> Decoder a -> Decoder a

string : Decoder String

int : Decoder Int

list : Decoder a -> Decoder (List a)

map2 :
  (a -> b -> c)
  -> Decoder a
  -> Decoder b
  -> Decoder c
succeed : a -> Decoder a

field : String -> Decoder a -> Decoder a

string : Decoder String

int : Decoder Int

list : Decoder a -> Decoder (List a)

map2 :
  (a -> b -> c)
  -> Decoder a
  -> Decoder b
  -> Decoder c

COMBINATORS

import Json.Decode as D

type alias Camp =
  { name : String
  , kids : List String
  , duration : Float
  }

campDecoder : D.Decoder Camp
campDecoder =
  D.map3 Camp
    (D.at [ "metadata", "name" ] D.string)
    (D.field "children" (D.list
    	(D.field "name" D.string)
    ))   
    (D.field "duration" D.float)
import Json.Decode as D
import Duration exposing (Duration)
type alias Camp =
  { name : String
  , kids : List String
  , duration : Duration
  }

campDecoder : D.Decoder Camp
campDecoder =
  D.map3 Camp
    (D.at [ "metadata", "name" ] D.string)
    (D.field "children" (D.list
    	(D.field "name" D.string)
    ))   
    (D.field "duration" 
      (D.map Duration.weeks D.float))
import Json.Decode as D
import Duration exposing (Duration)
type alias Camp =
  { name : String
  , kids : List String
  , duration : Duration
  }

campDecoder : D.Decoder Camp
campDecoder =
  D.map3 Camp
    (D.at [ "metadata", "name" ] D.string)
    (D.field "children" (D.list
    	(D.field "name" D.string)
    ))   
    (D.field "duration" 
      (D.map Duration.weeks D.float))
weeks : Float -> Duration
import Json.Decode as D
import Duration exposing (Duration)
type alias Camp =
  { name : String
  , kids : List String
  , duration : Duration
  }

campDecoder : D.Decoder Camp
campDecoder =
  D.map3 Camp
    (D.at [ "metadata", "name" ] D.string)
    (D.field "children" (D.list
    	(D.field "name" D.string)
    ))   
    (D.field "duration" 
      (D.map Duration.weeks D.float))
weeks : Float -> Duration

👆 Click me 👆

Json 2 Elm

{
  "name": "Super Camp",
  "duration": 7.0,
  "children": ["Sébastien", "Thomas"]
}

GraphQL

query {
  human(id: "1001") {
    name
    homePlanet
  }
}
query : SelectionSet (Maybe Human) RootQuery
query =
    Query.human { id = Id "1001" } humanSelection

type alias HumanData =
    { name : String, homePlanet : Maybe String    }

humanSelection : SelectionSet Human StarWars.Object.Human
humanSelection =
    SelectionSet.map2 HumanData
        Human.name
        Human.homePlanet

Entirely type safe requests

Type classes

Type classes

JSON decoding example:

  • automatically "derive" the decoders!

Yeah!

Type classes

JSON decoding example:

  • automatically "derive" the decoders!
  • manually write the instance

How to find the implementation?

Type classes

JSON decoding example:

  • automatically "derive" the decoders!
  • manually write the instance
  • buttonDecoder : 
      ButtonType -> Decoder Button

Type classes

JSON decoding example:

  • automatically "derive" the decoders!
  • manually write the instance
  • buttonDecoder : 
      ButtonType -> Decoder Button

Rigidity

Type classes

Rigidity

Compilation time

Yeah!

How to find the implementation?

Type classes

Yeah!

How to find the implementation?

Code reuse

Abstraction

Rigidity

Compilation time

Type classes

Rigidity

Compilation time

Yeah!

How to find the implementation?

Code reuse

Abstraction

Cognitive & Skills overloading

Type classes

No Type Classes in Elm

(or in a really limited form)

Type classes

No Type Classes in Elm

(or in a really limited form)

We have newcomers go through the official Elm guide, we sit down with them to answer questions and do concrete work, and after a couple of weeks, we don’t get requests for help anymore.

 

https://www.humio.com/whats-new/blog/why-we-chose-elm-for-humio-s-web-ui

elm

make

download deps, compile, build really quickly

Type classes

No Type Classes in Elm

(or in a really limited form)

Related:

Internationalization

module Page.Team exposing
  (Model, Locale, view, ...)

type alias Locale =
  { team : String }

view : Locale -> Model -> Html Msg
view locale model =
  Html.text locale.team
module Lang.Fr exposing (locale)

import Global
import Page.Team
import Page.Book

locale : Global.Local
locale =
  { login = "Connexion"
  , logout = "Déconnexion"
  , teamPage = teamPage
  , bookPage = bookPage
  }
  
teamPage : Page.Team.Locale
teamPage =
  { team = "Équipe!" }
  
bookPage : Page.Book.Locale
bookPage =
  { book = "Livre!" }
module Lang.Fr exposing (locale)

import Global
import Page.Team
import Page.Book

locale : Global.Local
locale =
  { login = "Connexion"
  , logout = "Déconnexion"
  , teamPage = teamPage
  , bookPage = bookPage
  }
  
teamPage : Page.Team.Locale
teamPage =
  { team = "Équipe!" }
  
bookPage : Page.Book.Locale
bookPage =
  { book = "Livre!" }

Elm-review

Elm-review

Let users write rules PER PROJECT

E.g. forbid the use of \(\texttt{Html.button}\) and force the use of \(\texttt{Theme.button}\)

Elm-review

Some "global" rules

type SomeType
    = Used
    | Unused -- line can be removed

defaultValue = Used

toString : SomeType -> String
toString value =
    case value of
        Used -> "used"
        Unused -> "unused" -- line can be removed

Elm-review

Some "global" rules

type Effect
  = RequestUsersList
  | Toast String

perform : Effect -> Model -> (Model, Cmd Msg)

update msg model =
  let
    (newModel, eff) =
      case newModel.page of
        Page1 -> myUpdate1 msg model
        Page2 -> myUpdate2 msg model
  in
  perform eff newModel 

myUpdate1 : Msg -> Model -> (Model, Effect)
myUpdate2 : Msg -> Model -> (Model, Effect)
type alias Layout msg =
  { mainPanel : Html msg, sidebar : Sidebar }
  

myView1 : Model -> Layout msg
myView2 : Model -> Layout msg

render : Layout msg -> Html msg

view model =
  render <|
    case model.page of
      Page1 -> myView1 model
      Page2 -> myView2 model

Elm architecture is a set of low level primitives

Releases

Releases

Releases

1.5 year

1.5 year

Elm, a functional language?

Sébastien Besnier

@_sebbes_

Purescript bundle size:

  • https://discourse.purescript.org/t/what-is-the-state-of-the-art-minification-compression/1369/3 (may 2020)
  • https://www.reddit.com/r/purescript/comments/ltm38p/how_do_you_deal_with_the_giant_bundle_sizes_from/ (march 2021)

 

Purescript: Hallogen: elm-similar api

Elm, a functional language?

By sebbes

Elm, a functional language?

  • 1,086