Christopher Bloom
Frontend developer, lover of design systems, CSS architecture, and all things javascript.
Christopher Bloom, @illepic
Phase2 is a digital agency moving industry leading organizations forward with powerful ideas and executable strategies built on open technology. We are experts at building and designing websites, applications, and digital platforms that position our clients to engage with their target audiences in any channel, on any device, wherever they may be.
Now wire this all together! Good luck!
Photo by Rene Bernal on Unsplash
Photo by Zoltan Tasi on Unsplash
Amitai Burstein, www.gizra.com.
DrupalCon NOLA:
Frontend With Guarantees
DrupalCon Vienna:
Elm and Haskell, Getting Off the Island.
"No combination of JS libraries can ever give you this, yet it is all free and easy in Elm. Now these nice things are only possible because Elm builds upon 40+ years of work on typed functional languages."
add num1 num2 = num1 + num2
sayWoof animal = animal ++ " says woof!"
--
add 3 3 -- 6
sayWoof "cat" -- "cat says woof!"
function add(num1, num2) {
return num1 + num2;
}
function sayWoof(animal) {
return `${animal} says woof!`;
}
// --
add(3, 3) // 6
sayWoof('cat') // 'cat says woof!'
(If functions are so important in JS, why all those extra characters?)
mutateMe = 7
mutateOutside = mutateMe + 1
--
mutateOutside -- 8
mutateMe -- 7
-- NO MECHANISM TO CHANGE OUTSIDE VARS!
let mutateMe = 7;
function mutateOutside() {
mutateMe++;
return mutateMe;
}
// --
mutateOutside() // 8
mutateMe // 8
// OH NOES, SIDE EFFECT!
priceList =
[1, 2, 3, 4]
makeProfit price =
price * 1.5
markupInventory list =
List.map makeProfit list
--
markupInventory priceList -- 1.5, 3, 4.5, 6
const priceList = [1, 2, 3, 4];
function markupInventory(list) {
const profitList = [];
const length = list.length;
for (let i = 0; i < length; i++) {
profitList.push(list[i] * 1.5);
}
return profitList;
}
// --
markupInventory(priceList); // [1.5, 3, 4.5, 6]
babyAnimals a b =
"i love " ++ a ++ " and " ++ b
babyKoalas = babyAnimals "koalas"
--
babyKoalas "puppies" -- "i love koalas and puppies"
babyKoalas "kittens" -- "i love koalas and kittens"
babyKoalas "pandas" -- "i love koalas and pandas"
--
babyAnimals "koalas" "kittens"
-- "i love koalas and kittens"
function babyAnimals(a) {
return function(b) {
return `i love ${a} and ${b}`;
}
}
const babyKoala = babyAnimals('koalas');
//
babyKoala('puppies'); // 'i love koalas and puppies'
babyKoala('kittens'); // 'i love koalas and kittens'
babyKoala('pandas'); // 'i love koalas and pandas'
//
babyAnimals('koalas')('kittens');
// 'i love koalas and kittens'
list =
List.range 1 5
list
|> List.map (\n -> n * 2) -- [2,4,6,8,10]
|> List.filter (\n -> n > 6) -- [8,10]
|> List.map (\n -> n * n) -- [64,100]
import _ from 'lodash';
const list = _.range(1, 6);
_
.chain(list)
.map(n => n * 2) // [2,4,6,8,10]
.filter(n => n > 6) // [8,10]
.map(n => n * n) // [64,100]
.value() // [64,100]
+
-- Values
amBald : Bool
amBald = True
catNoise : String
catNoise = "meow"
nums : List Int
nums = [1, 2, 3]
-- Functions
sayMeow : String -> String
sayMeow animal =
animal ++ " says meow"
add : Int -> Int -> Int
add x y =
x + y
> sayMeow 19
-- TYPE MISMATCH --------------------------------------------- repl-temp-000.elm
The argument to function `sayMeow` is causing a mismatch.
3| sayMeow 19
^^
Function `sayMeow` is expecting the argument to be:
String
But it is:
number
type Disposition = Surly | Friendly | Ambivalent
type alias Cat = {
name: String,
weight: Float,
disposition: Disposition
}
seamus : Cat
seamus =
{ name = "Seamus"
, weight = 22.2
, disposition = Surly
}
--
seamus.name -- "Seamus"
seamus.weight -- 22.2
.name seamus -- "Seamus"
// Flow + Webpack + Babel config required!
/*@flow*/
type Disposition = 'Surly' | 'Friendly' | 'Ambivalent'
type Cat = {
name: string,
weight: number,
disposition: Disposition,
};
const seamus: Cat = {
name: 'Seamus',
weight: 22.2,
disposition: 'Surly',
};
+
+
+
type Disposition = Surly | Friendly | Ambivalent
type alias Cat = {
name: String,
weight: Float,
disposition: Disposition
}
seamus = Cat "Seamus" 22.2 Surly
debris = Cat "Debris" 9.1 Friendly
simone = Cat "Simone" 7.2 Ambivalent
--
piggySeamus = { seamus | weight = seamus.weight * 1.1 }
piggySeamus.weight -- 24.42 : Float
seamus.weight -- 22.2 : Float
type Disposition
= Surly
| Friendly
| Ambivalent
| Mix Disposition Disposition
-- type alias Cat = { ...
seamus = Cat "Seamus" 22.2 Surly
debris = Cat "Debris" 9.1 Friendly
simone = Cat "Simone" 7.2 (Mix Ambivalent Surly)
-- Special type built in to Elm
type Maybe a -- "a" here means "anything"
= Just a -- "Just have a user, Cat, value"
| Nothing -- "Or I don't have anything"
--
type alias User =
{ name : String
, age : Maybe Int
}
sue : User
sue =
{ name = "Sue", age = Nothing }
tom : User
tom =
{ name = "Tom", age = Just 24 }
canBuyAlcohol : User -> Bool
canBuyAlcohol user =
case user.age of
Nothing ->
False
Just age ->
age >= 21
--
canBuyAlcohol tom -- True
canBuyAlcohol sue -- False
--
myList : List String
myList = ["First", "Second"]
-- List.head : List a -> Maybe.Maybe a
case List.head myList of
Nothing ->
"Empty list!"
Just val ->
val
-- List.head myList returns a Maybe, NOT value
let myList = ['First', 'Second'];
myList[0]; // "First"
let myList = [];
myList[0]; // undefined, *KABOOOOOOM*
All data must be "decoded" and typed to flow into Elm.
--
getRandomGif : String -> Cmd Msg
getRandomGif topic =
let
url =
"https://api.giphy.com/v1/..." ++ topic
in
Http.send NewGif (Http.get url decodeGifUrl)
--
decodeGifUrl : Decode.Decoder String
decodeGifUrl =
Decode.at [ "data", "image_url" ] Decode.string
Returns Request type
Returns (Cmd Msg)
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
MorePlease ->
(model, getRandomGif model.topic)
NewGif (Ok newUrl) ->
(Model model.topic newUrl, Cmd.none)
NewGif (Err _) ->
(model, Cmd.none)
Elm chooses this if Request succedes
Elm chooses this if Request fails
Actually, possible because of the
Elm Architecture
(We'll get to that soon)
Elm is safe because there are no "null" values, types ensure consistency, and control statements force dealing with all possibilities.
Elm's got it.
Make a binary that includes the Elm runtime:
elm-make src/Main.elm --output=build/main.js
<script src="build/main.js"></script>
<script>
const node = document.getElementById('main');
const app = Elm.Main.embed(node);
</script>
Initialize with JavaScript:
Elm Runtime
Msg
update
Html
view
model
Msg
update
Html
view
model
When the user clicks on a button, it produces a message. That message is piped into the update function, producing a new model. We use the view function to show the new model on screen. And then we just repeat this forever!
By Christopher Bloom
Elm is a language that compiles to javascript that provides the features of many custom javascript libraries in one. Let's take a quick tour of neat things that Elm can do.
Frontend developer, lover of design systems, CSS architecture, and all things javascript.