Static in the Front,
Dynamic in the Back!
Matt Machuga
Lone Star PHP 2017
Slide 2
Slide 2 text
Have you joined
Slack
Come
fi
nd Machuga in the back.
Slide 3
Slide 3 text
Functions
ƒ : x ⟶ y
Slide 4
Slide 4 text
Functions in Math
f(x) = x * 2
y = x * 2
Slide 5
Slide 5 text
Functions in PHP
function double($x) { return $x * 2; }
function($x) { return $x * 2; }
Slide 6
Slide 6 text
Functions in JS
function double(x) { return x * 2; }
x => x * 2
Slide 7
Slide 7 text
Functions in Elm
double x = x * 2
\x -> x * 2
Slide 8
Slide 8 text
Elm
• Purely functional language
• Browser-based - compiles to JS
• ML family - Standard ML and Haskell inspired
• DO NOT LEAVE, PLEASE
• Haskell on easy-mode
• No runtime errors - no ‘unde
fi
ned’ is not a function
Slide 9
Slide 9 text
Functions in Elm
double x = x * 2
\x -> x * 2
Slide 10
Slide 10 text
Functions in Elm
msgTo name msg = msg ++ “ to “ ++ name
Slide 11
Slide 11 text
No content
Slide 12
Slide 12 text
Functions in Elm
msgTo : String -> String -> String
msgTo name msg = msg ++ “ to “ ++ name
Slide 13
Slide 13 text
Functions in Elm
• Statically typed
• Pure (free from side-effects)
Slide 14
Slide 14 text
No content
Slide 15
Slide 15 text
Let the runtime
do all the work!
Slide 16
Slide 16 text
Functions in Elm
• Statically typed
• Pure (free from side-effects)
• Only take one argument (technically)
• Automatically curried
• Have multi-argument syntax sugar
• Implicitly return last value
Mapping over Lists
$double = function($el) { return $el * 2; }
array_map($double, [1,2,3,4,5]);
# => [2,4,6,8,10]
double el = el * 2
List.map double [1,2,3,4,5]
-- [2,4,6,8,10]
Slide 28
Slide 28 text
Let’s build
something
Slide 29
Slide 29 text
GitHub Issues Viewer
• Enter a GitHub repo to view a list of its issues
• Show:
• Title
• Body
• Url
• Comment count
• Labels
Slide 30
Slide 30 text
Getting Started
Slide 31
Slide 31 text
No content
Slide 32
Slide 32 text
No content
Slide 33
Slide 33 text
No content
Slide 34
Slide 34 text
No content
Slide 35
Slide 35 text
No content
Slide 36
Slide 36 text
No content
Slide 37
Slide 37 text
No content
Slide 38
Slide 38 text
No content
Slide 39
Slide 39 text
q
Slide 40
Slide 40 text
elm-format
• Atom ran code through elm-format
• Saw we were missing module declaration
• Added module declaration as name of
fi
le
• Formatted code
Slide 41
Slide 41 text
elm-format
module Main exposing (..)
-- export all functions from this module
Slide 42
Slide 42 text
The Elm Compiler
The kindest compiler you will ever use
Slide 43
Slide 43 text
elm-make
• Analyzed our code
• Saw unsupported type returned from main
• Suggested
fi
xes
Slide 44
Slide 44 text
elm-make
The `main` value has an unsupported type.
I need Html, Svg, or a Program so I have
something to render on screen, but you gave me:
String
Slide 45
Slide 45 text
Static Compilers
Slide 46
Slide 46 text
elm-make
The `main` value has an unsupported type.
I need Html, Svg, or a Program so I have
something to render on screen, but you gave me:
String
Slide 47
Slide 47 text
No content
Slide 48
Slide 48 text
Warning
Top-level value `main` does not have a type
annotation.
I inferred the type annotation so you can copy it
into your code:
main : Html msg
Slide 49
Slide 49 text
No content
Slide 50
Slide 50 text
What is `Html msg`?
• Main returns with the type `Html msg`
• Means it is a chunk of Html that can produce
values of any type.
• Ignore this for now
Slide 51
Slide 51 text
elm-live
• Development server for Elm code
• Live Reloads on successful compilation
Slide 52
Slide 52 text
No content
Slide 53
Slide 53 text
No content
Slide 54
Slide 54 text
Did Elm really
compile to HTML?
Yup - and JS to be fair
Slide 55
Slide 55 text
But it can compile to
just JS, right?
Yup
Slide 56
Slide 56 text
elm-live
$ elm live Main.elm --output=elm.js
Slide 57
Slide 57 text
No content
Slide 58
Slide 58 text
Loading Elm in App
Elm.Main.embed(
document.getElementById("app")
);
Slide 59
Slide 59 text
No content
Slide 60
Slide 60 text
Let’s Move it to Elm!
Views as functions
Slide 61
Slide 61 text
No content
Slide 62
Slide 62 text
No content
Slide 63
Slide 63 text
No content
Slide 64
Slide 64 text
No content
Slide 65
Slide 65 text
No content
Slide 66
Slide 66 text
Unquali
fi
ed Imports
-- Instead of typing
Html.Attributes.class
Html.Attributes.placeholder
-- etc
-- We can type
class
placeholder
Slide 67
Slide 67 text
No content
Slide 68
Slide 68 text
Convert HTML
Slide 69
Slide 69 text
To Elm
inputView =
form [ class "form" ]
[ div [ class "form-group" ]
[ div [ class "row" ]
[ div [ class "col-md-8" ]
[ input
[ type_ "text"
, class "input-lg form-control"
, placeholder "Enter a GitHub Repo (Ex: elm-lang/elm)"
] []
]
, div [ class "col-md-4" ]
[ input
[ type_ "submit"
, class "btn btn-primary btn-lg"
, value "Load Issues"
] []
]
]
]
]
Slide 70
Slide 70 text
Html Element Signature
div : List (Html.Attribute msg)
-> List (Html.Html msg)
-> Html.Html msg
-- div takes a List of Attributes
-- and a List of child Html Elements
-- and returns an Html Element
Slide 71
Slide 71 text
Html Element Signature
inputView =
form [ class "form" ]
[ div [ class "form-group" ]
[ div [ class "row" ]
[ div [ class "col-md-8" ]
[ input
[ type_ "text"
, class "input-lg form-control"
, placeholder "Enter a GitHub Repo (Ex: elm-lang/elm)"
] []
]
, div [ class "col-md-4" ]
[ input
[ type_ "submit"
, class "btn btn-primary btn-lg"
, value "Load Issues"
] []
]
]
]
]
Slide 72
Slide 72 text
Html Element Signature
inputView =
form [ class "form" ]
[ div [ class "form-group" ]
[ div [ class "row" ]
[ div [ class "col-md-8" ]
[ input
[ type_ "text"
, class "input-lg form-control"
, placeholder "Enter a GitHub Repo (Ex: elm-lang/elm)"
] []
]
, div [ class "col-md-4" ]
[ input
[ type_ "submit"
, class "btn btn-primary btn-lg"
, value "Load Issues"
] []
]
]
]
]
Slide 73
Slide 73 text
Let’s Do Another!
Slide 74
Slide 74 text
No content
Slide 75
Slide 75 text
No content
Slide 76
Slide 76 text
No content
Slide 77
Slide 77 text
2
Slide 78
Slide 78 text
No content
Slide 79
Slide 79 text
No content
Slide 80
Slide 80 text
No content
Slide 81
Slide 81 text
ಠ_ಠ
Slide 82
Slide 82 text
Whoops!
We didn’t add this function to main
Slide 83
Slide 83 text
No content
Slide 84
Slide 84 text
No content
Slide 85
Slide 85 text
One More Level
Labels probably deserve their own views
Slide 86
Slide 86 text
No content
Slide 87
Slide 87 text
No content
Slide 88
Slide 88 text
Views are Converted!
However, they do nothing but display static HTML
Slide 89
Slide 89 text
Let’s Model our Data
Slide 90
Slide 90 text
Our app has
• A repository name to search
• A list of issues to display
Slide 91
Slide 91 text
type alias
• Create a domain-speci
fi
c type
• Composable of other types
• “Alias this structure by this name”
• Keep type signatures clean
Slide 92
Slide 92 text
type alias Model
type alias Model =
{ repo : String
, issues : List GitHubIssue
}
Slide 93
Slide 93 text
Recall from earlier
• We want our issues to show:
• Title
• Body
• Url
• Comment count
• Labels
Slide 94
Slide 94 text
type alias GitHubIssue
type alias GitHubIssue =
{ title : String
, body : String
, url : String
, comments : Int
, labels : List GitHubLabel
}
Slide 95
Slide 95 text
type alias GitHubLabel
type alias GitHubLabel =
{ title : String
, color : String
}
Slide 96
Slide 96 text
No content
Slide 97
Slide 97 text
Create Initial Data
Slide 98
Slide 98 text
No content
Slide 99
Slide 99 text
No content
Slide 100
Slide 100 text
No content
Slide 101
Slide 101 text
What do we have?
• List containing n-number of issues
• HTML element that takes a list of child elements
Slide 102
Slide 102 text
So what we want is...
a List of IssueView
Slide 103
Slide 103 text
Remember Mapping?
Slide 104
Slide 104 text
No content
Slide 105
Slide 105 text
More guidance
The 1st argument to function `map` is causing a mismatch.
Function `map` is expecting the 1st argument to be:
a -> VirtualDom.Node msg
But it is:
Html msg
It looks like a function needs 1 more argument.
Slide 106
Slide 106 text
No content
Slide 107
Slide 107 text
Type Mismatch
Function `map` is expecting the 1st argument to be:
a -> VirtualDom.Node msg
But it is:
Html msg
It looks like a function needs 1 more argument.
Slide 108
Slide 108 text
No content
Slide 109
Slide 109 text
Render Issue Data
Slide 110
Slide 110 text
No content
Slide 111
Slide 111 text
No content
Slide 112
Slide 112 text
No content
Slide 113
Slide 113 text
Time to Add
Behavior
Slide 114
Slide 114 text
Html.program
Slide 115
Slide 115 text
Html.program
main =
Html.program
{ init : (Model, Cmd msg)
, view : Model -> Html msg
, update : msg -> Model -> (Model, Cmd msg)
, subscriptions : Model -> Sub msg
}
Slide 116
Slide 116 text
Subscriptions are
Out of Scope
But still very useful!
Slide 117
Slide 117 text
No content
Slide 118
Slide 118 text
Cmd.none
Runtime, take a break.
Slide 119
Slide 119 text
No content
Slide 120
Slide 120 text
No content
Slide 121
Slide 121 text
No content
Slide 122
Slide 122 text
What can our app do?
• Set Repository Name
• Fetch Issues
Slide 123
Slide 123 text
type - Union Types
• A type to represent complex data
• A type to represent acceptable types
Slide 124
Slide 124 text
Example from Elm Docs
type User = Named String | Anonymous
activeUsers : List User
activeUsers =
[ Anonymous, Named “Machuga”]
Slide 125
Slide 125 text
type Msg
type Msg
= SetRepo String
| FetchIssues
Slide 126
Slide 126 text
No content
Slide 127
Slide 127 text
Determinism
Slide 128
Slide 128 text
Pattern Matching
Slide 129
Slide 129 text
case..of - like switch,
but awesome!
Slide 130
Slide 130 text
case...of
update : msg -> Model -> ( Model, Cmd msg )
update msg model =
init
Slide 131
Slide 131 text
case...of
update : Msg -> Model -> ( Model, Cmd msg )
update msg model =
init
Slide 132
Slide 132 text
case...of
update : Msg -> Model -> ( Model, Cmd msg )
update msg model =
case msg of
SetRepo repo ->
....
Slide 133
Slide 133 text
No content
Slide 134
Slide 134 text
Type Mismatch
The de
fi
nition of `main` does not match its type annotation.
The type annotation for `main` says it is a:
Program Never Model msg
But the de
fi
nition (shown above) is a:
Program Never Model Msg
Your type annotation uses type variable `msg` which means any type of
value can
fl
ow through. Your code is saying it CANNOT be anything though! Maybe
change your type annotation to be more speci
fi
c? Maybe the code has a problem?
More at:
Slide 135
Slide 135 text
Update Main’s Signature
Slide 136
Slide 136 text
No content
Slide 137
Slide 137 text
Determinism
This `case` does not have branches for all possibilities.
You need to account for the following values:
Main.FetchIssues
Add a branch to cover this pattern!
If you are seeing this error for the
fi
rst 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!
Slide 138
Slide 138 text
No content
Slide 139
Slide 139 text
Updating a Record
Slide 140
Slide 140 text
Updating a Record
{ model | key = value }
-- Read as:
-- Model, such that key is equal to value
Slide 141
Slide 141 text
No content
Slide 142
Slide 142 text
Still Needs Wired Up!
Slide 143
Slide 143 text
No content
Slide 144
Slide 144 text
No content
Slide 145
Slide 145 text
No content
Slide 146
Slide 146 text
No content
Slide 147
Slide 147 text
IT DOES A THING!
Slide 148
Slide 148 text
Hook up other
events
Slide 149
Slide 149 text
No content
Slide 150
Slide 150 text
Representing
Something That May
Not Exist
So call me “Maybe”?
You can boo at that one
Slide 151
Slide 151 text
There is no null
Slide 152
Slide 152 text
Maybe
type Maybe = Just a | Nothing
-- Maybe String says:
-- The value is either just a string
-- or it is nothing
-- Developer must account for both
Slide 153
Slide 153 text
No content
Slide 154
Slide 154 text
No content
Slide 155
Slide 155 text
No content
Slide 156
Slide 156 text
No content
Slide 157
Slide 157 text
Now the views
Slide 158
Slide 158 text
No content
Slide 159
Slide 159 text
No content
Slide 160
Slide 160 text
Check Out Elm!
Slide 161
Slide 161 text
Resources
• Pragmatic Studio Elm Courses
• http://elm-lang.org
• KnowThen Elm Course
• Daily Drip
Slide 162
Slide 162 text
I’m Matt Machuga
Slide 163
Slide 163 text
Improve your application with theory!
https://bitsandtrees.com
Slide 164
Slide 164 text
Erie, PA
Slide 165
Slide 165 text
Thanks!
Slide 166
Slide 166 text
No content
Slide 167
Slide 167 text
Warning: Boss Fight
If we made it this far, I’m shocked, and you’re awesome!
Slide 168
Slide 168 text
elm-lang/http
$ elm package install elm-lang/http
Slide 169
Slide 169 text
elm-lang/http
import Http
import Json.Decode as Decode exposing
(Decoder,
fi
eld, succeed)
Slide 170
Slide 170 text
Add More Functionality
type Msg
= SetRepo String
| FetchIssues
| LoadIssues (Result Http.Error (List GitHubIssue))
Slide 171
Slide 171 text
What?
LoadIssues (Result Http.Error (List GitHubIssue))
-- LoadIssues takes
-- a Result that will return either
-- Http.Error
-- List GitHubIssue
Slide 172
Slide 172 text
Consider a Promise
promise.then(yay, oops)
Slide 173
Slide 173 text
Http.send
Slide 174
Slide 174 text
Http.get
Slide 175
Slide 175 text
GitHub Issues Endpoint
Slide 176
Slide 176 text
Declare Data
Structure
Slide 177
Slide 177 text
Json Decoding
Slide 178
Slide 178 text
Type Constructor
GitHubIssue title body url comments labels
Slide 179
Slide 179 text
Our First Command
Slide 180
Slide 180 text
fetchIssues
Slide 181
Slide 181 text
Whoa
-- Construct the get, pass to send, the result will be
sent to LoadIssues
Http.send
LoadIssues
<|
Http.get (repoUrl repo) (Decode.list issueDecoder)