James Morcom (@morcs, morcs.com)
Imagine a world...
Just functions and data!
Also...
https://bit.ly/2HqPNqX
Input (Int) | Output (Int) |
---|---|
-1 | 1 |
0 | 0 |
1 | 1 |
2 | 4 |
3 | 9 |
... | ... |
Input (Int) | Output (Int) |
---|---|
-1 | 1 |
0 | 0 |
1 | 1 |
... | ... |
circumference r =
2 * pi * r
add x y = x + y
pi = 3.142
result = add 3 5
-- result == 7
results =
[ circumference 2
, add 3 4
, 12
]
numbers = [1, 2, 3, 4, 5]
https://morcs.com/introduction-to-elm/
Ctrl-click "View Exercise"
Try compiling - should get an error
Elm code
HTML output
main = table [] []
-- hit compile, compiler validates HTML!
<table></table>
main = table [ class "table" ] []
-- again, hit compile to validate HTML
<table class="table"></table>
main =
table [ class "table" ] [
tr [] []
]
-- try the FORMAT button!
<table class="table">
<tr></tr>
</table>
main =
table [ class "table" ]
[ tr []
[ th [] []
]
-- hit compile, valid HTML!
]
<table class="table">
<tr> <th></th> </tr>
</table>
main =
table [ class "table" ]
[ tr []
[ th [ scope "row" ] [ text "Elm" ] ]
]
-- should start to see output
<table class="table">
<tr> <th scope="row">Elm</th> </tr>
</table>
main =
table [ class "table" ]
[ tr []
[ th [ scope "row" ] [ text "Elm" ]
, td [] [ text "10" ]
]
]
<table class="table">
<tr> <th scope="row">Elm</th> <td>10</td> </tr>
</table>
main =
table [ class "table" ]
[ renderRow
]
renderRow =
tr []
[ th [ scope "row" ] [ text "Elm" ]
, td [] [ text "10" ]
]
<table class="table">
<tr> <th scope="row">Elm</th> <td>10</td> </tr>
</table>
main =
table [ class "table" ]
[ renderRow "Elm"
, renderRow "React"
]
renderRow : String -> Html msg -- type annotation
renderRow name =
tr []
[ th [ scope "row" ] [ text name ]
, td [] [ text "10" ]
]
<table class="table">
<tr> <th scope="row">Elm</th> <td>10</td> </tr>
<tr> <th scope="row">React</th> <td>10</td> </tr>
</table>
main =
table [ class "table" ]
[ renderRow "Elm" 10 -- web component!
, renderRow "React" 9
]
renderRow : String -> Int -> Html msg
renderRow name score =
tr []
[ th [ scope "row" ] [ text name ]
, td [] [ text (toString score) ]
]
<table class="table">
<tr> <th scope="row">Elm</th> <td>10</td> </tr>
<tr> <th scope="row">React</th> <td>9</td> </tr>
</table>
https://morcs.com/introduction-to-elm/
Instructions/markup are on this page!
james : { name : String, age : Int }
james =
{ name = "James"
, age = 12
}
james : (String, Int)
james = ("James", 12)
Records
Tuples
model :
{ cards : List Card
, loaded : Bool
, errorMessage : String
, hasError : Bool
}
model =
{ cards = []
, loaded = True
, errorMessage = "Cards didn't load"
, hasError = True
}
type Model
= Loading
| Success (List Card)
| Error String
case model of
Loading ->
-- show a loading spinner
Success cards ->
-- render all the cards
Error msg ->
-- show msg with red styling
model = Error "Badness happened"
type Bool
= True
| False
type List a
= NonEmptyList a (List a)
| Empty
https://morcs.com/introduction-to-elm/
The essense of every Elm program:
The back-end isn't ready yet
...but the client wants to see what it'll look like in various states
Lets add some buttons so they can switch between states.
model : model
view : model -> Html msg
update : msg -> model -> model
type Model
= Loading
| Success (List Card)
| Error String
type Msg
= TestSuccess
| TestError String
Buttons
https://morcs.com/introduction-to-elm/
type Maybe a
= Nothing
| Just a
Only Maybes
var empty = new List<Card>();
var card = empty.FirstOrDefault();
var card = empty.First();
var name = card.Name
Exception!!!
Exception!!!
List.head : List a -> Maybe a
C#
Elm
card = List.head []
name = card.name
Won't compile!!!
name = case List.head [] of
Nothing ->
"Anonymous"
Just card ->
card.name
Input (List Int) | Output (Int) ? |
---|---|
[] | BOOM! / null |
[1] | 1 |
[1,2] | 1 |
[2] | 2 |
... | ... |
First / FirstOrDefault
Input (List Int) | Output (Maybe Int) |
---|---|
[] | Nothing |
[1] | Just 1 |
[1,2] | Just 1 |
[2] | Just 2 |
... | ... |
List.head
https://morcs.com/introduction-to-elm/
type Result error value
= Ok value
| Err error
Only Results
init : (model, Cmd msg)
update : msg -> model -> (model, Cmd msg)
view : model -> Html msg
subscriptions : model -> Sub msg
https://morcs.com/introduction-to-elm/
https://morcs.com/introduction-to-elm/
...if we only have pure functions
Input | Output |
---|---|
Card X was clicked | Model with Card X selected |
Load more was clicked | Go fetch URL (with callback) |
result =
List.map circumference <| List.filter isEven numbers
result =
List.map circumference numbers
result =
numbers
|> List.filter isEven
|> List.map circumference
result =
List.map circumference (List.filter isEven numbers)
type Maybe a
= Nothing
| Just a
type List a
= Empty
| NonEmptyList a (List a)
cardName : Maybe Card -> String
cardName selected =
selected
|> Maybe.map .name
|> Maybe.withDefault "-- not selected --"
selected = Just { name = "Brian" }
result = cardName selected
-- result == "Brian"
selected = Nothing
result = cardName selected
-- result == "-- not selected --"
add x y = x + y
addThree = add 3
result = addThree 4
circumference = \r -> 2 * pi * r
add = \x -> (\y -> x + y)
addThree = add 3 -- \y -> 3 + y
Lambda syntax
add : number -> number -> number
addThree : number -> number
result : number