Slide 1

Slide 1 text

realkinetic.com | @real_kinetic Don’t Worry About Monads Just build it already

Slide 2

Slide 2 text

realkinetic.com | @real_kinetic Beau Lyddon Managing Partner at Real Kinetic We mentor engineering teams to unleash your full potential. @lyddonb linkedin.com/in/beau-lyddon github.com/lyddonb

Slide 3

Slide 3 text

realkinetic.com | @real_kinetic We’re going to focus on Strongly-Typed Functional Languages in the ML family

Slide 4

Slide 4 text

realkinetic.com | @real_kinetic Haskell, Purescript, Elm, OCaml, Idris, F#

Slide 5

Slide 5 text

realkinetic.com | @real_kinetic Although many of the concepts apply to other functional languages: Scala, lisp family, Rust, etc

Slide 6

Slide 6 text

realkinetic.com | @real_kinetic So why am I doing this?

Slide 7

Slide 7 text

realkinetic.com | @real_kinetic Because the world (especially our industry) will be better if we get more to embrace functional programming principles

Slide 8

Slide 8 text

realkinetic.com | @real_kinetic And for that we need to start shipping code based around functional programming

Slide 9

Slide 9 text

realkinetic.com | @real_kinetic This is not a direct “teach you the language” presentation

Slide 10

Slide 10 text

realkinetic.com | @real_kinetic It’s more of a “get comfortable with syntax, structure and terms” presentation

Slide 11

Slide 11 text

realkinetic.com | @real_kinetic It’s also a kill the FUD (Fear, Uncertainty, Doubt) Presentation

Slide 12

Slide 12 text

realkinetic.com | @real_kinetic I want to remove the barriers that may be keeping you from diving in

Slide 13

Slide 13 text

realkinetic.com | @real_kinetic This comes from my own experience attempting to learn these languages

Slide 14

Slide 14 text

realkinetic.com | @real_kinetic I have/had imposter syndrome from a lacking mathematics background

Slide 15

Slide 15 text

realkinetic.com | @real_kinetic And I struggle to learn programming from books

Slide 16

Slide 16 text

realkinetic.com | @real_kinetic Much of the code and documentation seemed quite advanced

Slide 17

Slide 17 text

realkinetic.com | @real_kinetic Difficult to separate struggles from lack of familiarity of syntax and complex/ advanced constructs

Slide 18

Slide 18 text

realkinetic.com | @real_kinetic But …

Slide 19

Slide 19 text

realkinetic.com | @real_kinetic One thing I want to make clear …

Slide 20

Slide 20 text

realkinetic.com | @real_kinetic This is not going to be an anti-terminology presentation

Slide 21

Slide 21 text

realkinetic.com | @real_kinetic I was that person, I was wrong

Slide 22

Slide 22 text

realkinetic.com | @real_kinetic The terminology can be quite helpful as you learn it

Slide 23

Slide 23 text

realkinetic.com | @real_kinetic Instead I hope to show …

Slide 24

Slide 24 text

realkinetic.com | @real_kinetic You don’t need to understand all of the terminology (While still appreciating it’s value)

Slide 25

Slide 25 text

realkinetic.com | @real_kinetic You don’t need to be great at math

Slide 26

Slide 26 text

realkinetic.com | @real_kinetic Or even go through books

Slide 27

Slide 27 text

realkinetic.com | @real_kinetic To be productive in functional languages today

Slide 28

Slide 28 text

realkinetic.com | @real_kinetic And still get many of the advantages these languages provide

Slide 29

Slide 29 text

realkinetic.com | @real_kinetic This is why we will mostly focus on Elm

Slide 30

Slide 30 text

realkinetic.com | @real_kinetic Elm is a compile to Javascript mostly, front-end (in the browser) focused language (Yes, it can be used in other environments)

Slide 31

Slide 31 text

realkinetic.com | @real_kinetic Elm is meant to be the more accessible strongly- typed (ML family) language

Slide 32

Slide 32 text

realkinetic.com | @real_kinetic It is designed for you to get work done and shipped to production

Slide 33

Slide 33 text

realkinetic.com | @real_kinetic If you leave this presentation excited you can go spend a couple of hours doing the getting started with Elm

Slide 34

Slide 34 text

realkinetic.com | @real_kinetic And build something real by the time your done

Slide 35

Slide 35 text

realkinetic.com | @real_kinetic Elm sacrifices some power to allow more access

Slide 36

Slide 36 text

realkinetic.com | @real_kinetic They purposely avoid non-common mathematical terms, etc

Slide 37

Slide 37 text

realkinetic.com | @real_kinetic But hopefully once you’ve built some stuff in Elm you’ll be excited to learn about this magic that’s available in these other languages

Slide 38

Slide 38 text

realkinetic.com | @real_kinetic And then you can dig as deep into terminology, formalism, etc as you would prefer

Slide 39

Slide 39 text

realkinetic.com | @real_kinetic And you’ll get even more benefits appearing in your programs

Slide 40

Slide 40 text

realkinetic.com | @real_kinetic Fair warning: Once you start, you may not be able to stop :)

Slide 41

Slide 41 text

realkinetic.com | @real_kinetic Now, let’s get started

Slide 42

Slide 42 text

realkinetic.com | @real_kinetic The first hurdle is the syntax

Slide 43

Slide 43 text

realkinetic.com | @real_kinetic We’re going to go very fast through the syntax

Slide 44

Slide 44 text

realkinetic.com | @real_kinetic I want to get to the fun stuff at the end

Slide 45

Slide 45 text

realkinetic.com | @real_kinetic This is all taken from the Elm documentation and starter material (tutorials, etc)

Slide 46

Slide 46 text

realkinetic.com | @real_kinetic Let’s make a quick counter

Slide 47

Slide 47 text

realkinetic.com | @real_kinetic In Python

Slide 48

Slide 48 text

realkinetic.com | @real_kinetic from jinja2 import Template def main(): return SomeProcessor(model, view, update) class Msg: Increment = "INCREMENT" Decrement = "DECREMENT" class Model(object): def __init__(self, count): self.count = count def model(): return Model(0) def update(msg, model): if msg == Msg.Increment: model.count += 1 elif msg == Msg.Decrement: model.count -= 1 return model TEMPLATE = """
-
{{ count }} +
""" def view(model): template = Template(TEMPLATE) return template.render(count=model.count)

Slide 49

Slide 49 text

realkinetic.com | @real_kinetic Now, Elm http://elm-lang.org/examples/buttons

Slide 50

Slide 50 text

realkinetic.com | @real_kinetic import Html exposing (Html, button, div, text) import Html.Events exposing (onClick) main = Html.beginnerProgram { model = model, view = view, update = update } model = 0 type Msg = Increment | Decrement update msg model = case msg of Increment -> model + 1 Decrement -> model - 1 view model = div [] [ button [ onClick Decrement ] [ text "-" ] , div [] [ text (toString model) ] , button [ onClick Increment ] [ text "+" ] ]

Slide 51

Slide 51 text

realkinetic.com | @real_kinetic from jinja2 import Template def main(): return SomeProcessor(model, view, update) class Msg: Increment = "INCREMENT" Decrement = "DECREMENT" class Model(object): def __init__(self, count): self.count = count def model(): return Model(0) def update(msg, model): if msg == Msg.Increment: model.count += 1 elif msg == Msg.Decrement: model.count -= 1 return model TEMPLATE = """
-
{{ count }} +
""" def view(model): template = Template(TEMPLATE) return template.render(count=model.count)

Slide 52

Slide 52 text

realkinetic.com | @real_kinetic Where are the types?

Slide 53

Slide 53 text

realkinetic.com | @real_kinetic They are not required as they are inferred.

Slide 54

Slide 54 text

realkinetic.com | @real_kinetic But it is recommend to annotate your code

Slide 55

Slide 55 text

realkinetic.com | @real_kinetic Let’s start with our Python example

Slide 56

Slide 56 text

realkinetic.com | @real_kinetic class Model(object): def __init__(self, count): """Initialize a counter. args: count (Int) """ self.count = count def model(): """Initializes a new model. returns: Model """ return Model(0) def update(msg, model): """Updates a model based off the message and existing model state. args: msg (Msg) model (Model) returns: Model """ if msg == Msg.Increment: model.count += 1 elif msg == Msg.Decrement: model.count -= 1 return model def view(model): """Renders our view with our template and the passed in model state. args: model (Model) returns: String """ template = Template(TEMPLATE) return template.render(count=model.count)

Slide 57

Slide 57 text

realkinetic.com | @real_kinetic And now Elm

Slide 58

Slide 58 text

realkinetic.com | @real_kinetic import Html exposing (Html, button, div, text) import Html.Events exposing (onClick) Program Never Model Msg main = Html.beginnerProgram { model = model, view = view, update = update } type alias Model = Int model : Model model = 0 type Msg = Increment | Decrement update : Msg -> Model -> Model update msg model = case msg of Increment -> model + 1 Decrement -> model - 1 view : Model -> Html Msg view model = div [] [ button [ onClick Decrement ] [ text "-" ] , div [] [ text (toString model) ] , button [ onClick Increment ] [ text "+" ] ]

Slide 59

Slide 59 text

realkinetic.com | @real_kinetic import Html exposing (Html, button, div, text) import Html.Events exposing (onClick) main = Html.beginnerProgram { model = model, view = view, update = update } model = 0 type Msg = Increment | Decrement update msg model = case msg of Increment -> model + 1 Decrement -> model - 1 view model = div [] [ button [ onClick Decrement ] [ text "-" ] , div [] [ text (toString model) ] , button [ onClick Increment ] [ text "+" ] ]

Slide 60

Slide 60 text

realkinetic.com | @real_kinetic Let’s dive in and step through so we can get more comfortable with the syntax

Slide 61

Slide 61 text

realkinetic.com | @real_kinetic With type definitions the last type is the return type

Slide 62

Slide 62 text

realkinetic.com | @real_kinetic -- A single type means it takes 0 arguments thing : Int thing = 0 -- This takes 2 arguments each of int and -— returns and int add : Int -> Int -> Int add x y = x + y

Slide 63

Slide 63 text

realkinetic.com | @real_kinetic -- You can alias a type type alias Things = Int -- This allows us to make more readable types. thing : Things thing = 0

Slide 64

Slide 64 text

realkinetic.com | @real_kinetic -- This is a sum or union type (specifically a boolean type in this case). -- You may also see: tagged or disjoint —- unions or variant types type Msg = Increment | Decrement

Slide 65

Slide 65 text

realkinetic.com | @real_kinetic -- Sum Types can have as many options as you'd like type Cars = Mustang | Camero | Taurus | Fit | Focus —- With Boolean there are 2 possible options type Bool = False | True

Slide 66

Slide 66 text

realkinetic.com | @real_kinetic Why called Sum Type?

Slide 67

Slide 67 text

realkinetic.com | @real_kinetic You can find the total number of possible values by adding them

Slide 68

Slide 68 text

realkinetic.com | @real_kinetic Bool has 2 possible options: (False + True)

Slide 69

Slide 69 text

realkinetic.com | @real_kinetic Cars has 5 possible options: (Mustang + Camero + Taurus + Fit + Focus)

Slide 70

Slide 70 text

realkinetic.com | @real_kinetic Sum Types are a bit like Enums in other languages

Slide 71

Slide 71 text

realkinetic.com | @real_kinetic Enums in Python

Slide 72

Slide 72 text

realkinetic.com | @real_kinetic from enum import Enum class Color(Enum): RED = 1 GREEN = 2 BLUE = 3 >>> print(Color.RED) Color.RED >>> type(Color.RED) >>> isinstance(Color.GREEN, Color) True >>> print(Color.RED.name) RED

Slide 73

Slide 73 text

realkinetic.com | @real_kinetic Enums in Javascript Kinda

Slide 74

Slide 74 text

realkinetic.com | @real_kinetic // Enum var DaysEnum = Object.freeze({"monday":1, "tuesday":2, "wednesday":3 }); DaysEnum.monday = 33; // Throws an error in strict mode console.log(DaysEnum.tuesday); // expected output: 2

Slide 75

Slide 75 text

realkinetic.com | @real_kinetic But not quite. It usually takes quite a bit of code to make a proper Sum type in other languages

Slide 76

Slide 76 text

realkinetic.com | @real_kinetic Full Sum Type in Javascript https://medium.com/fullstack-academy/better-js-cases-with-sum-types-92876e48fd9f

Slide 77

Slide 77 text

realkinetic.com | @real_kinetic const PointTag = Symbol('Point') const Point = (x, y) => { if (typeof x !== 'number') throw TypeError('x must be a Number') if (typeof y !== 'number') throw TypeError('y must be a Number') return { x, y, tag: PointTag } } const CircleTag = Symbol('Circle') const RectangleTag = Symbol('Rectangle') const Shape = { Circle: (center, radius) => { if (center.tag !== PointTag) throw TypeError('center must be a Point') if (typeof radius !== 'number') throw TypeError('radius must be a Number') return { center, radius, tag: CircleTag } }, Rectangle: (corner1, corner2) => { if (corner1.tag !== PointTag) throw TypeError('corner1 must be a Point') if (corner2.tag !== PointTag) throw TypeError('corner2 must be a Point') return { corner1, corner2, tag: RectangleTag } } }

Slide 78

Slide 78 text

realkinetic.com | @real_kinetic const circ1 = Shape.Circle(Point(2, 3), 6.5) const circ2 = Shape.Circle(Point(5, 1), 3) const rect1 = Shape.Rectangle(Point(1.5, 9), Point(7, 7)) const rect2 = Shape.Rectangle(Point(0, 3), Point(3, 0)) console.log('Is circ1 a circle?', circ1.tag === CircleTag) // true console.log('Is circ2 a circle?', circ2.tag === CircleTag) // true console.log('Is rect1 a rectangle?', rect1.tag === RectangleTag) // true console.log('Is rect2 a rectangle?', rect2.tag === RectangleTag) // true const rect3 = Shape.Rectangle(Point(1, 2), 9) // ERROR: corner2 must be a Point

Slide 79

Slide 79 text

realkinetic.com | @real_kinetic Pattern Matching

Slide 80

Slide 80 text

realkinetic.com | @real_kinetic type MyBool = MyFalse | MyTrue handleBool : MyBool -> String handleBool myBool = case myBool of MyTrue -> "It's my true" MyFalse -> "It's my false” handleBool MyTrue > "It's My True" handleBool MyFalse > "It's My False"

Slide 81

Slide 81 text

realkinetic.com | @real_kinetic class MyBoo(Enum): MyTrue = 1 MyFalse = 0 def handle_bool(my_bool): if my_bool == MyBoo.MyTrue: return "It's my true" elif my_bool == MyBoo.MyFalse: return "It's my false” handle_bool(MyBoo.MyTrue) > "It's my true" handle_bool(MyBoo.MyFalse) > "It's my false"

Slide 82

Slide 82 text

realkinetic.com | @real_kinetic But what about …

Slide 83

Slide 83 text

realkinetic.com | @real_kinetic handle_bool(“THIS CAN BE ANYTHING”) > None

Slide 84

Slide 84 text

realkinetic.com | @real_kinetic def handle_bool_all(my_bool): if my_bool == MyBoo.MyTrue: return "It's my true" elif my_bool == MyBoo.MyFalse: return "It's my false” else: return “Oops” handle_bool_all(“THIS CAN BE ANYTHING!") > "Oops"

Slide 85

Slide 85 text

realkinetic.com | @real_kinetic var MyBool = Object.freeze({"myTrue": 1, "myFalse": 0}); const handleMyBool = (myBool) => { switch (myBool) { case MyBool.myTrue: return "It's my true" case MyBool.myFalse: return "It's my false" default: "Oops!" } }

Slide 86

Slide 86 text

realkinetic.com | @real_kinetic Btw, there’s nothing stopping us from doing …

Slide 87

Slide 87 text

realkinetic.com | @real_kinetic def handle_bool_missing(my_bool): if my_bool == MyBoo.MyTrue: return "It's my true”

Slide 88

Slide 88 text

realkinetic.com | @real_kinetic handleBool : MyBool -> String handleBool myBool = case myBool of MyTrue -> "It's my true"

Slide 89

Slide 89 text

realkinetic.com | @real_kinetic Missing Patterns This `case` does not have branches for all possibilities. You need to account for the following values: Main.MyFalse Add a branch to cover this pattern! If you are seeing this error for the first time, check out these hints: The recommendations about wildcard patterns and `Debug.crash` are important!

Slide 90

Slide 90 text

realkinetic.com | @real_kinetic handleBool : MyBool -> String handleBool myBool = case myBool of MyTrue -> "It's my true" MyFalse -> "It's my false” Default -> "The default"

Slide 91

Slide 91 text

realkinetic.com | @real_kinetic Naming Error Cannot find pattern `Default`

Slide 92

Slide 92 text

realkinetic.com | @real_kinetic handleBool : MyBool -> String handleBool myBool = case myBool of MyTrue -> "It's my true" _ -> "The default” —- WORKS!

Slide 93

Slide 93 text

realkinetic.com | @real_kinetic handleBool : MyBool -> String handleBool myBool = case myBool of MyTrue -> "It's my true" MyFalse -> "It's my false” _ -> "The default"

Slide 94

Slide 94 text

realkinetic.com | @real_kinetic Redundant Pattern The following pattern is redundant. Remove it. Any value with this shape will be handled by a previous pattern.

Slide 95

Slide 95 text

realkinetic.com | @real_kinetic Functions, Arrows, Partial Application, and Currying

Slide 96

Slide 96 text

realkinetic.com | @real_kinetic Sounds harder than it is

Slide 97

Slide 97 text

realkinetic.com | @real_kinetic Javascript, Python, Ruby support partial application and currying

Slide 98

Slide 98 text

realkinetic.com | @real_kinetic -- This takes 2 integers and returns and Int add2Things : Int -> Int -> Int add2Things x y = x + y

Slide 99

Slide 99 text

realkinetic.com | @real_kinetic -- But it doesn't have to. —- You can pass only one argument add2Things 1

Slide 100

Slide 100 text

realkinetic.com | @real_kinetic This is called: partial application (You are partially applying arguments to a function)

Slide 101

Slide 101 text

realkinetic.com | @real_kinetic -- This means when you don't pass all of the —- arguments in you will get back a function. -- So: add2Things 1 -- Returns a function (Int -> Int)

Slide 102

Slide 102 text

realkinetic.com | @real_kinetic —- You can read that like: add2ThingsPartial : Int -> (Int -> Int) —- This is now a function that takes a single: Int —- And returns a function of: (Int -> Int)

Slide 103

Slide 103 text

realkinetic.com | @real_kinetic -- Let's set that to a variable let addTo1 = add2Things 1

Slide 104

Slide 104 text

realkinetic.com | @real_kinetic -- Now addTo1 is a function that takes a single argument. It looks like addTo1 : Int -> Int addTo1 x = add2Things 1 -- or addTo1 x = 1 + x -- So if we call it addTo1 2 == 3

Slide 105

Slide 105 text

realkinetic.com | @real_kinetic Python

Slide 106

Slide 106 text

realkinetic.com | @real_kinetic def add2Things(x): return lambda y: x + y addTo1 = add2Things(1) >>> addTo1(2) 3

Slide 107

Slide 107 text

realkinetic.com | @real_kinetic Comes with built-in for partial application

Slide 108

Slide 108 text

realkinetic.com | @real_kinetic from functools import partial def add2Things(x, y): return x + y addTo1 = partial(add2Things, 1) >>> addTo1(2) 3

Slide 109

Slide 109 text

realkinetic.com | @real_kinetic Javascript

Slide 110

Slide 110 text

realkinetic.com | @real_kinetic // As mentioned this can be done in Javascript var add2Things = function (x, y){ return function (y){ x + y; } } > add2Things(1); function (y){ x + y; } > var addTo1 = add2Things(1); > addTo1(2); > 3

Slide 111

Slide 111 text

realkinetic.com | @real_kinetic You now have seen partial application, currying and what are called:

Slide 112

Slide 112 text

realkinetic.com | @real_kinetic Higher Order Functions

Slide 113

Slide 113 text

realkinetic.com | @real_kinetic A function that does at least one of the following:

Slide 114

Slide 114 text

realkinetic.com | @real_kinetic Takes one or more functions as arguments

Slide 115

Slide 115 text

realkinetic.com | @real_kinetic Or returns a function as its result

Slide 116

Slide 116 text

realkinetic.com | @real_kinetic That’s all higher order functions are

Slide 117

Slide 117 text

realkinetic.com | @real_kinetic Functions that take and/or return functions themselves

Slide 118

Slide 118 text

realkinetic.com | @real_kinetic We will come back to that later and use it often.

Slide 119

Slide 119 text

realkinetic.com | @real_kinetic It’s important in functional languages to get comfortable with treating functions like data that can be passed around.

Slide 120

Slide 120 text

realkinetic.com | @real_kinetic Let’s go through more to keep getting familiar with syntax

Slide 121

Slide 121 text

realkinetic.com | @real_kinetic type Msg = Increment | Decrement -- This takes 2 arguments, —- a Msg and a Model and then returns a Model update : Msg -> Model -> Model update msg model = case msg of Increment -> model + 1 Decrement -> model - 1

Slide 122

Slide 122 text

realkinetic.com | @real_kinetic const helloWorldReducer = (state=0, action) => { switch(action.type){ case PLUS: return Object.assign({}, state, state + 1) case MINUS: return Object.assign({}, state, state - 1) default: return state } }

Slide 123

Slide 123 text

realkinetic.com | @real_kinetic type Msg = Increment | Decrement -- This takes a single type of Model —- and returns a single type of Html Msg view : Model -> Html Msg view model = div [] [ button [ onClick Decrement ] [ text "-" ] , div [] [ text (toString model) ] , button [ onClick Increment ] [ text "+" ] ]

Slide 124

Slide 124 text

realkinetic.com | @real_kinetic -- Html is another type alias for: type alias Html msg = VirtualDom.Node msg -- This type as a "generic" type. -- The msg could be anything: type alias Html a = VirtualDom.Node a // Java Generics: public interface Html {} Html myHtml = new MyHtml(myMSG)

Slide 125

Slide 125 text

realkinetic.com | @real_kinetic import React from 'react' const Hello = ( {onClickPlus, onClickMinus, message} ) => { return(

{message}

+ -
) } export default Hello

Slide 126

Slide 126 text

realkinetic.com | @real_kinetic What if we want to store multiple values

Slide 127

Slide 127 text

realkinetic.com | @real_kinetic -- Records! type alias Counter = { value : Int , count : Int }

Slide 128

Slide 128 text

realkinetic.com | @real_kinetic Records are often called Product Types or Tuples

Slide 129

Slide 129 text

realkinetic.com | @real_kinetic Why? It's a compound type that is formed by a sequence of types and is commonly denoted:

Slide 130

Slide 130 text

realkinetic.com | @real_kinetic (T1, T2, ..., Tn) or T1 x T2 x ... x Tn

Slide 131

Slide 131 text

realkinetic.com | @real_kinetic They correspond to cartesian products thus products types

Slide 132

Slide 132 text

realkinetic.com | @real_kinetic By allowing you to be named they become records

Slide 133

Slide 133 text

realkinetic.com | @real_kinetic Or potentially in other languages ... structs, classes, etc

Slide 134

Slide 134 text

realkinetic.com | @real_kinetic So you find the total number of options by multiplying the maximum value of each option. https://www.stephanboyer.com/post/18/algebraic-data-types

Slide 135

Slide 135 text

realkinetic.com | @real_kinetic type alias Counter = { value : Int , count : Int } counter : Counter counter = { value = 0 , count = 0 }

Slide 136

Slide 136 text

realkinetic.com | @real_kinetic -- Accessing properties getValue : Counter -> Int getValue counter = counter.value getValue counter > 0 getValue { value = 2, count = 1} > 2

Slide 137

Slide 137 text

realkinetic.com | @real_kinetic -- Shorthand accessors getValueShort : Counter -> Int getValueShort counter = .value counter getValueShort counter > 0 getValueShort { value = 2, count = 1} > 2

Slide 138

Slide 138 text

realkinetic.com | @real_kinetic -- Updating Single Property updateValue : Int -> Counter -> Counter updateValue newValue existingCounter = { existingCounter | value = newValue } updateValue 10 counter > { value = 10, count 0 }

Slide 139

Slide 139 text

realkinetic.com | @real_kinetic -- Updating Multiple Properties updateValueWithCount : Int -> Counter -> Counter updateValueWithCount newValue existingCounter = { existingCounter | value = newValue , count = existingCounter.count + 1 } updateValueWithCount 10 counter > { value = 10, count 1 }

Slide 140

Slide 140 text

realkinetic.com | @real_kinetic Python

Slide 141

Slide 141 text

realkinetic.com | @real_kinetic dict_counter = {"value": 1, "count": 1} >>> dict_counter["value"] 1 >>> dict_counter["value"] = 2 >>> dict_counter["value"] 2 >>> dict_counter["count"] 1 def update(val, rec): cnt["value"] = val cnt["count"] = int(cnt("count", 0)) + 1 return cut >>> update(33, dict_counter) >>> dict_counter["value"] 33 >>> dict_counter["count"] 2

Slide 142

Slide 142 text

realkinetic.com | @real_kinetic class Counter(object): def __init__(self, val): self._value = val self._count = 0 @property def count(self): return self._count @property def value(self): return self._value @value.setter def value(self, value): self._value = value self._count += 1 >>> cnt = Counter(1) >>> cnt.value 1 >>> cnt.count 1 >>> cnt.value = 22 >>> cnt.value 22 >>> cnt.count 2

Slide 143

Slide 143 text

realkinetic.com | @real_kinetic Javascript

Slide 144

Slide 144 text

realkinetic.com | @real_kinetic var counter = { _count: 0, _value: 0}; Object.defineProperty(counter, "count", { get: function() { return this._count; } }) Object.defineProperty(counter, "value", { get: function() { return this._value; }, set: function(v) { this._count++; return this._value = val; } }) >>> counter.value; 0 >>> counter.count; 0 >>> counter.value = 44; >>> counter.value; 44 >>> counter.count; 1

Slide 145

Slide 145 text

realkinetic.com | @real_kinetic Extensible Records in Elm

Slide 146

Slide 146 text

realkinetic.com | @real_kinetic type alias Record2 = { value : Int , count : Int , foo : String } type alias Record3 = { value : Int , count : Int , bar : String } type alias Record4 = { value : Int , foobar : String }

Slide 147

Slide 147 text

realkinetic.com | @real_kinetic -- Extensible record alias type alias ValueRecord a = { a | value : Int } getValue2 : ValueRecord a -> Int getValue2 valRec = valRec.value -- COMPILES: getValue2 record2 -- COMPILES: getValue2 record3 -- COMPILES: getValue2 record4 -- COMPILES: getValue2 { value = 0 } -- FAILURE: getValue2 { foo = 0 } -- FAILURE: getValue2 {}

Slide 148

Slide 148 text

realkinetic.com | @real_kinetic We can make our update function more generic and readable

Slide 149

Slide 149 text

realkinetic.com | @real_kinetic updateRecord : Int -> { a | value : Int, count : Int } -> { a | value : Int, count : Int } updateRecord rec newValue = { rec | value = newValue , count = count + 1 } -- COMPILES: updateRecord 1 record2 -- COMPILES: updateRecord 1 record3 -- DOESN'T COMPILE: updateRecord 1 record4

Slide 150

Slide 150 text

realkinetic.com | @real_kinetic type alias ValueRecord a b = { a | value : b, count : Int } updateRecord : Int -> ValueRecord a b -> ValueRecord a b updateRecord rec newValue = { rec | value = newValue , count = count + 1 } -- COMPILES: updateRecord 1 record2 -- COMPILES: updateRecord 1 record3 -- COMPILES: updateRecord “a” { value = “b”, count = 0 }

Slide 151

Slide 151 text

realkinetic.com | @real_kinetic Nulls?

Slide 152

Slide 152 text

realkinetic.com | @real_kinetic Do NOT exist

Slide 153

Slide 153 text

realkinetic.com | @real_kinetic Yay!

Slide 154

Slide 154 text

realkinetic.com | @real_kinetic If we can't have a null we need something to help us

Slide 155

Slide 155 text

realkinetic.com | @real_kinetic What does a NULL mean?

Slide 156

Slide 156 text

realkinetic.com | @real_kinetic It means we have “nothing” when we might have been expecting “something”

Slide 157

Slide 157 text

realkinetic.com | @real_kinetic So what about something called “either”?

Slide 158

Slide 158 text

realkinetic.com | @real_kinetic type Either a b = Left a | Right b

Slide 159

Slide 159 text

realkinetic.com | @real_kinetic This is something we could use (and do use often) but our need is less generic.

Slide 160

Slide 160 text

realkinetic.com | @real_kinetic Each side isn’t some general structure. One means something very specific.

Slide 161

Slide 161 text

realkinetic.com | @real_kinetic So what about?

Slide 162

Slide 162 text

realkinetic.com | @real_kinetic type Result error value = Ok value | Err error

Slide 163

Slide 163 text

realkinetic.com | @real_kinetic This is closer but our result isn’t really an error it’s “Nothing”

Slide 164

Slide 164 text

realkinetic.com | @real_kinetic So maybe we could go with:

Slide 165

Slide 165 text

realkinetic.com | @real_kinetic type Maybe a = Just a | Nothing

Slide 166

Slide 166 text

realkinetic.com | @real_kinetic Now we’re on to something.

Slide 167

Slide 167 text

realkinetic.com | @real_kinetic Maybe we Just have a value (of type a) or we have Nothing

Slide 168

Slide 168 text

realkinetic.com | @real_kinetic giveMeIfGreatherThan0 : Int -> Maybe Int giveMeIfGreatherThan0 val = if val > 0 then Just val else Nothing giveMeIfGreatherThan0 10 > Just 10 giveMeIfGreatherThan0 -23 > Nothing

Slide 169

Slide 169 text

realkinetic.com | @real_kinetic But now we have this structure that we have to deal with

Slide 170

Slide 170 text

realkinetic.com | @real_kinetic And we don’t want our code to look like Go’s error handling code

Slide 171

Slide 171 text

realkinetic.com | @real_kinetic Where you have this same code everywhere …

Slide 172

Slide 172 text

realkinetic.com | @real_kinetic f, err := os.Open("filename.ext") if err != nil { log.Fatal(err) }

Slide 173

Slide 173 text

realkinetic.com | @real_kinetic Thankfully there are functions in the maybe package to help us out

Slide 174

Slide 174 text

realkinetic.com | @real_kinetic withDefault : a -> Maybe a -> a withDefault default maybe = case maybe of Just value -> value Nothing -> default withDefault 10 (Just 15) -- 15 withDefault 10 (Nothing) -- 10 withDefault "foo" (Just "bar") -- "bar" withDefault "foo" (Nothing) -- “foo”

Slide 175

Slide 175 text

realkinetic.com | @real_kinetic -- Map map : (a -> b) -> Maybe a -> Maybe b map f maybe = case maybe of Just value -> Just (f value) Nothing -> Nothing

Slide 176

Slide 176 text

realkinetic.com | @real_kinetic So we take in a function of (a -> b), Maybe a and return Maybe b

Slide 177

Slide 177 text

realkinetic.com | @real_kinetic Let’s break this down

Slide 178

Slide 178 text

realkinetic.com | @real_kinetic We may have an “a” and if do we want to get back a “b”

Slide 179

Slide 179 text

realkinetic.com | @real_kinetic So the function we give needs to take an “a” and give back a “b”

Slide 180

Slide 180 text

realkinetic.com | @real_kinetic The map will take care of the actual application

Slide 181

Slide 181 text

realkinetic.com | @real_kinetic If you give it a “Just a” it will take the “a” out of the “Just” and apply your function

Slide 182

Slide 182 text

realkinetic.com | @real_kinetic It will take the result of that function and put that inside a “Just”

Slide 183

Slide 183 text

realkinetic.com | @real_kinetic If you give it “Nothing” it will skip applying the function and will just give you “Nothing”

Slide 184

Slide 184 text

realkinetic.com | @real_kinetic Let’s create an function of (a -> b) and walk through

Slide 185

Slide 185 text

realkinetic.com | @real_kinetic add1 : Int -> Int add1 val = val + 1 -- In this case we use the same type. —- It doesn't have to be 2 different types. -- but we can do that positiveMessage : Int -> String positiveMessage val = if val > 0 then "I'm a positive message!" else "I'm not so postivie :("

Slide 186

Slide 186 text

realkinetic.com | @real_kinetic And now when we “run” it:

Slide 187

Slide 187 text

realkinetic.com | @real_kinetic map add1 (Just 10) > Just 11 map add1 Nothing > Nothing map positiveMessage (Just 10) > Just "I'm a positive message!” map positiveMessage (Just -23) > Just "I'm not so positive :(“ map positiveMessage Nothing > Nothing

Slide 188

Slide 188 text

realkinetic.com | @real_kinetic Javascript

Slide 189

Slide 189 text

realkinetic.com | @real_kinetic We’re going to cheat and use a javascript maybe library https://github.com/alexanderjarvis/maybe

Slide 190

Slide 190 text

realkinetic.com | @real_kinetic import { maybe } from 'maybes' import { maybe, just, nothing } from 'maybes' const value = maybe(1) // Just(1) value.isJust() // true value.isNothing() // false value.just() // 1 (or could error since JS is not safe) value.map(v => v + 1) // Just(2) const empty = maybe(null) empty.isJust() // false empty.isNothing() // true empty.just() // throws error empty.map(v => v + 1) // noop (No Operation) empty.map(v => v.toUpperCase()).orJust('hello') // 'hello'

Slide 191

Slide 191 text

realkinetic.com | @real_kinetic Lists

Slide 192

Slide 192 text

realkinetic.com | @real_kinetic simpleList : List Int simpleList = [1, 2, 3, 4] insertIntoSimpleList : Int -> List Int insertIntoSimpleList num = num :: simpleList insertIntoSimpleList 10 > [10, 1, 2, 3, 4] insertIntoSimpleList 333 > [333, 1, 2, 3, 4]

Slide 193

Slide 193 text

realkinetic.com | @real_kinetic Loops

Slide 194

Slide 194 text

realkinetic.com | @real_kinetic Elm doesn’t have them

Slide 195

Slide 195 text

realkinetic.com | @real_kinetic We instead use functions (Remember that passing functions around like data thing)

Slide 196

Slide 196 text

realkinetic.com | @real_kinetic We’ll start with a “fold” (AKA: Reduce)

Slide 197

Slide 197 text

realkinetic.com | @real_kinetic -- This is a fold left of Ints -- The left means we reduce (or traverse) from the left foldlInt : (Int -> List Int -> List Int) -> Int -> List Int -> Int foldlInt func aggVal list = case list of [] -> aggVal x :: xs -> foldl func (func x aggVal) xs

Slide 198

Slide 198 text

realkinetic.com | @real_kinetic Ooh, we’ve got that “higher order functions” thing again (A function that takes a function in this case)

Slide 199

Slide 199 text

realkinetic.com | @real_kinetic It’s first argument is a function of two values that returns one (Int -> List Int -> List Int)

Slide 200

Slide 200 text

realkinetic.com | @real_kinetic It then takes some value to accumulate into. Something that can accumulate like a list, a string, a number.

Slide 201

Slide 201 text

realkinetic.com | @real_kinetic It also takes a starting value

Slide 202

Slide 202 text

realkinetic.com | @real_kinetic foldlInt (::) [] [1,2,3] —- (::) is called `cons` (::) : a -> List a -> List a

Slide 203

Slide 203 text

realkinetic.com | @real_kinetic So this takes a function of “cons” or “insert at 0 index” (insert into the 0 index of a list)

Slide 204

Slide 204 text

realkinetic.com | @real_kinetic As well as an empty list to accumulate into

Slide 205

Slide 205 text

realkinetic.com | @real_kinetic And of course our starting list

Slide 206

Slide 206 text

realkinetic.com | @real_kinetic Let’s step through our fold

Slide 207

Slide 207 text

realkinetic.com | @real_kinetic Thus starting from the left of [1,2,3] we prepend 1 to our starting empty list []. We now have [1]

Slide 208

Slide 208 text

realkinetic.com | @real_kinetic And then inserting 2 into the 0 index of [1] We now have [2, 1]

Slide 209

Slide 209 text

realkinetic.com | @real_kinetic And then we finish by prepending the 3 to [2,1]: [3,2,1]

Slide 210

Slide 210 text

realkinetic.com | @real_kinetic -- We also can fold from the right foldrInt : (Int -> List Int -> List Int) -> Int -> List Int -> Int foldrInt (::) [] [1,2,3] == [1,2,3] -- Using the same arguments as before we end —- up with the same list we started -- Since we started from the right we prepend 3 —- we have [3] -- And the inserting 2 into the 0 index we have [2, 3] -- And then we finish by prepending the 1: [1,2,3]

Slide 211

Slide 211 text

realkinetic.com | @real_kinetic Python

Slide 212

Slide 212 text

realkinetic.com | @real_kinetic from functools import reduce def insert(arr, val): arr.insert(0, val) return arr arr = [1, 2, 3] >>> reduce(insert, [], arr) [3, 2, 1]

Slide 213

Slide 213 text

realkinetic.com | @real_kinetic Javascript

Slide 214

Slide 214 text

realkinetic.com | @real_kinetic const arr = [1, 2, 3]; const reducer = (accumulator, currentValue) => { accumulator.push(currentValue); return accumulator }; > arr.reduce(reducer, []); [ 1, 2, 3] const array1 = [1, 2, 3, 4]; const reducer = (accumulator, currentValue) => accumulator + currentValue; // 1 + 2 + 3 + 4 > array1.reduce(reducer); 10 // 5 + 1 + 2 + 3 + 4 > array1.reduce(reducer, 5); 15

Slide 215

Slide 215 text

realkinetic.com | @real_kinetic Back to Elm

Slide 216

Slide 216 text

realkinetic.com | @real_kinetic We of course can pass in different types of functions

Slide 217

Slide 217 text

realkinetic.com | @real_kinetic What if we use the max function?

Slide 218

Slide 218 text

realkinetic.com | @real_kinetic foldlInt max 0 [1,2,3] == 3 -- We give it the builtin max function —- that is a more generic version of: max : Int -> Int -> Int max x y = if x > y then x else y

Slide 219

Slide 219 text

realkinetic.com | @real_kinetic We can then make a nice function to get the maximum integer

Slide 220

Slide 220 text

realkinetic.com | @real_kinetic maximumInt : List Int -> Int maximumInt list = case list of [] -> 0 [x] -> x x :: xs -> foldl max x xs

Slide 221

Slide 221 text

realkinetic.com | @real_kinetic But this kinda sucks. If we give an empty list we get back a 0.

Slide 222

Slide 222 text

realkinetic.com | @real_kinetic maximumInt [1,2] == 2 maximumInt [1] == 1 maximumInt [] == 0 -- Blech!

Slide 223

Slide 223 text

realkinetic.com | @real_kinetic This is standard in other types of languages but we’re using strong-type FP for a reason

Slide 224

Slide 224 text

realkinetic.com | @real_kinetic What if we introduce a “Maybe”?

Slide 225

Slide 225 text

realkinetic.com | @real_kinetic maximumInt : List Int -> Maybe Int maximumInt list = case list of x :: xs -> Just (foldl max x xs) _ -> Nothing

Slide 226

Slide 226 text

realkinetic.com | @real_kinetic Now it’s obvious to us when our result has no maximum value as we gave it no values

Slide 227

Slide 227 text

realkinetic.com | @real_kinetic maximumInt [1,2] == Just 2 maximumInt [1] == Just 1 maximumInt [] == Nothing

Slide 228

Slide 228 text

realkinetic.com | @real_kinetic And if we want to get a 0 value when the list is empty we just use what we already have:

Slide 229

Slide 229 text

realkinetic.com | @real_kinetic withDefault 0 (maximumInt [1,2]) == 2 withDefault 0 (maximumInt [1]) == 1 withDefault 0 (maximumInt []) == 0

Slide 230

Slide 230 text

realkinetic.com | @real_kinetic While we're here, we do this function chaining quite a bit.

Slide 231

Slide 231 text

realkinetic.com | @real_kinetic And we're not a lisp so we'd like to avoid all of the parentheses. (foo (bar 1 (another “a” “b”)) 3)

Slide 232

Slide 232 text

realkinetic.com | @real_kinetic Thankfully elm gives us some nice symbols to use (These symbols are actually functions known as infix operators)

Slide 233

Slide 233 text

realkinetic.com | @real_kinetic withDefault 0 <| maximumInt [1,2] > 2 withDefault 0 <| maximumInt [1] > 1 withDefault 0 <| maximumInt [] > 0

Slide 234

Slide 234 text

realkinetic.com | @real_kinetic This allows us to do nice, readable chaining when we have many functions

Slide 235

Slide 235 text

realkinetic.com | @real_kinetic withDefault 0 <| maximumInt <| range 0 10 > 10 -- other direction: [1,2,3] |> maximumInt |> withDefault 0 > 3

Slide 236

Slide 236 text

realkinetic.com | @real_kinetic Let’s go back and tweak our fold functions to make them more generic

Slide 237

Slide 237 text

realkinetic.com | @real_kinetic foldl : (a -> b -> b) -> b -> List a -> b foldl func acc list = case list of [] -> acc x :: xs -> foldl func (func x acc) xs

Slide 238

Slide 238 text

realkinetic.com | @real_kinetic Now our fold function can work on many different data types.

Slide 239

Slide 239 text

realkinetic.com | @real_kinetic With generic fold functions what can we do?

Slide 240

Slide 240 text

realkinetic.com | @real_kinetic It turns out, quite a lot.

Slide 241

Slide 241 text

realkinetic.com | @real_kinetic map : (a -> b) -> List a -> List b map f xs = foldr (\x acc -> f x :: acc) [] xs map (\x -> x + 1) [1,2,3] > [2,3,4] add1 : Int -> Int add1 x = x + 1 map add1 [1,2,3] > [2,3,4]

Slide 242

Slide 242 text

realkinetic.com | @real_kinetic Javascript & Python

Slide 243

Slide 243 text

realkinetic.com | @real_kinetic // Javascript var arr = [1, 2, 3] > arr.map(x => x + 1) [2, 3, 4] # Python arr = [1, 2, 3] >>> map(lambda x: x + 1, arr) [2, 3, 4]

Slide 244

Slide 244 text

realkinetic.com | @real_kinetic There are all kinds of functions for working with lists in the List.elm module in the standard library

Slide 245

Slide 245 text

realkinetic.com | @real_kinetic Many of these leverage fold (and each other)

Slide 246

Slide 246 text

realkinetic.com | @real_kinetic We end up with a library of functions that will look very similar to what you find in Python, Javascript, Ruby, etc

Slide 247

Slide 247 text

realkinetic.com | @real_kinetic isEmpty, length, reverse, member, head, tail, filter, take, drop, sum, all, etc

Slide 248

Slide 248 text

realkinetic.com | @real_kinetic Immutability

Slide 249

Slide 249 text

realkinetic.com | @real_kinetic Elm is functional and immutable ... so can we store and mutate state?

Slide 250

Slide 250 text

realkinetic.com | @real_kinetic Yes, but we need to leverage “let” expressions

Slide 251

Slide 251 text

realkinetic.com | @real_kinetic forty : Int forty = let twentyFour = 3 * 8 sixteen = 4 ^ 2 in twentyFour + sixteen

Slide 252

Slide 252 text

realkinetic.com | @real_kinetic You just can't reassign the same variable

Slide 253

Slide 253 text

realkinetic.com | @real_kinetic bad : Int bad = let twentyFour = 3 * 8 twentyFour = 20 + 4 in twentyFour

Slide 254

Slide 254 text

realkinetic.com | @real_kinetic This will not compile. You will get this message:

Slide 255

Slide 255 text

realkinetic.com | @real_kinetic There are multiple values named `twentyFour` in this let-expression. Search through this let-expression, find all the values named `twentyFour`, and give each of them a unique name.

Slide 256

Slide 256 text

realkinetic.com | @real_kinetic good : Int good = let twentyFour = 3 * 8 newTwentyFour = 20 + 4 in newTwentyFour -- This will compile.

Slide 257

Slide 257 text

realkinetic.com | @real_kinetic 2 Other Notes on Let expressions

Slide 258

Slide 258 text

realkinetic.com | @real_kinetic You can assign functions

Slide 259

Slide 259 text

realkinetic.com | @real_kinetic And you can provide type annotations

Slide 260

Slide 260 text

realkinetic.com | @real_kinetic letFunctions : Int letFunctions = let hypotenuse a b = sqrt (a^2 + b^2) name : String name = "Hermann" increment : Int -> Int increment n = n + 1 in increment 10

Slide 261

Slide 261 text

realkinetic.com | @real_kinetic Those are the basics you need to be successful in Elm

Slide 262

Slide 262 text

realkinetic.com | @real_kinetic But if you’re still nervous don’t worry.

Slide 263

Slide 263 text

realkinetic.com | @real_kinetic You have another tool available to you

Slide 264

Slide 264 text

realkinetic.com | @real_kinetic The compiler

Slide 265

Slide 265 text

realkinetic.com | @real_kinetic Don’t fight the compiler. Let it help you.

Slide 266

Slide 266 text

realkinetic.com | @real_kinetic You don’t even have to provide the types

Slide 267

Slide 267 text

realkinetic.com | @real_kinetic The compiler will give you the types!!!

Slide 268

Slide 268 text

realkinetic.com | @real_kinetic update msg model = case msg of Increment -> model + 1 Decrement -> model - 1

Slide 269

Slide 269 text

realkinetic.com | @real_kinetic ============= WARNINGS =============== -- missing type annotation - /…/elm-counter/src/elm/Main.elm Top-level value `update` does not have a type annotation. 29| update msg model = ^^^^^^ I inferred the type annotation so you can copy it into your code: update : Msg -> Model -> Model

Slide 270

Slide 270 text

realkinetic.com | @real_kinetic update : Msg -> Model -> Model update msg model = case msg of Increment -> model + 1 Decrement -> model - 1

Slide 271

Slide 271 text

realkinetic.com | @real_kinetic And it will even let you know when you might be overly strict

Slide 272

Slide 272 text

realkinetic.com | @real_kinetic ============= WARNINGS =============== -- missing type annotation - /…/elm-counter/src/elm/Main.elm Top-level value `update` does not have a type annotation. 29| update msg model = ^^^^^^ I inferred the type annotation so you can copy it into your code: update : Msg -> { a | value : Int } -> ( { a | value : Int }, Cmd Msg )

Slide 273

Slide 273 text

realkinetic.com | @real_kinetic The Elm compiler is a really helpful tool.

Slide 274

Slide 274 text

realkinetic.com | @real_kinetic Don’t fight it.

Slide 275

Slide 275 text

realkinetic.com | @real_kinetic Don’t attempt to out smart it and write the perfect code if you’re unsure.

Slide 276

Slide 276 text

realkinetic.com | @real_kinetic Just get something in and compile.

Slide 277

Slide 277 text

realkinetic.com | @real_kinetic One last syntax thing before we move into architecture and building applications

Slide 278

Slide 278 text

realkinetic.com | @real_kinetic Debugging

Slide 279

Slide 279 text

realkinetic.com | @real_kinetic In the standard library (core) we are provided some very helpful debugging functions

Slide 280

Slide 280 text

realkinetic.com | @real_kinetic Debug.log log : String -> a -> a

Slide 281

Slide 281 text

realkinetic.com | @real_kinetic Log a tagged value on the developer console, and then return the value.

Slide 282

Slide 282 text

realkinetic.com | @real_kinetic 1 + log "number" 1 -- equals 2, logs "number: 1" length (log "start" []) -- equals 0, logs "start: []"

Slide 283

Slide 283 text

realkinetic.com | @real_kinetic Notice that log is not a pure function! It should only be used for investigating bugs or performance problems.

Slide 284

Slide 284 text

realkinetic.com | @real_kinetic myFunc : Action -> String myFunc action = case action of act1 -> "It's act 1" act2 -> "It's act 2"

Slide 285

Slide 285 text

realkinetic.com | @real_kinetic myFunc : Action -> String myFunc action = let _ = Debug.log "Action: " action in case action of act1 -> "It's act 1" act2 -> "It's act 2"

Slide 286

Slide 286 text

realkinetic.com | @real_kinetic myFunc : Action -> String myFunc action = case (Debug.log "Action: " action) of act1 -> "It's act 1" act2 -> "It's act 2"

Slide 287

Slide 287 text

realkinetic.com | @real_kinetic Debug.crash crash : String -> a

Slide 288

Slide 288 text

realkinetic.com | @real_kinetic Crash the program with an error message. This is an uncatchable error, intended for code that is soon-to-be-implemented.

Slide 289

Slide 289 text

realkinetic.com | @real_kinetic USE THIS if you want to do some testing while you are partway through writing a function.

Slide 290

Slide 290 text

realkinetic.com | @real_kinetic DO NOT USE THIS IF you want to do some typical try- catch exception handling. Use the Maybe or Result libraries instead.

Slide 291

Slide 291 text

realkinetic.com | @real_kinetic The Elm Architecture

Slide 292

Slide 292 text

realkinetic.com | @real_kinetic Model Update View

Slide 293

Slide 293 text

realkinetic.com | @real_kinetic Model The state of your application

Slide 294

Slide 294 text

realkinetic.com | @real_kinetic Update A way to update your state

Slide 295

Slide 295 text

realkinetic.com | @real_kinetic View A way to view your state as HTML

Slide 296

Slide 296 text

realkinetic.com | @real_kinetic http://elmprogramming.com/subscriptions.html

Slide 297

Slide 297 text

realkinetic.com | @real_kinetic This architecture is very important as it helps us with …

Slide 298

Slide 298 text

realkinetic.com | @real_kinetic Side Effects

Slide 299

Slide 299 text

realkinetic.com | @real_kinetic Historical FUD: “You can’t build anything in real in functional programming because it’s ‘pure’”

Slide 300

Slide 300 text

realkinetic.com | @real_kinetic Then came along Philip Wadler

Slide 301

Slide 301 text

realkinetic.com | @real_kinetic Monads for Functional Programming Wadler, 1992 http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf

Slide 302

Slide 302 text

realkinetic.com | @real_kinetic We finally mentioned Monads

Slide 303

Slide 303 text

realkinetic.com | @real_kinetic When people are freaked out by these languages it’s often around side effects and those specific MONADS

Slide 304

Slide 304 text

realkinetic.com | @real_kinetic IO ()

Slide 305

Slide 305 text

realkinetic.com | @real_kinetic getMeetupNameAndVenues :: GroupId -> IO [(Text, Text)] getMeetupNameAndVenues groupId = getWith (eventsOptions groupId) meetupEventsUrl >>= asValue >>= ((^.. responseBody . key "results" . _Array . traverse) >>> map ((^. key "name" . _String) &&& (^. key "venue" . key "name" . _String) ) >>> return

Slide 306

Slide 306 text

realkinetic.com | @real_kinetic Purescript

Slide 307

Slide 307 text

realkinetic.com | @real_kinetic Eff () Aff ()

Slide 308

Slide 308 text

realkinetic.com | @real_kinetic forall eff. Eff (console :: CONSOLE, random :: RANDOM | eff) Unit

Slide 309

Slide 309 text

realkinetic.com | @real_kinetic eval :: Query ~> H.ComponentDSL State Query Void (Aff (ajax :: AX.AJAX | eff)) eval = case _ of SetUsername username next -> do H.modify (_ { username = username, result = Nothing :: Maybe String }) pure next MakeRequest next -> do username <- H.gets _.username H.modify (_ { loading = true }) response <- H.liftAff $ AX.get ("https://api.github.com/users/" <> username) H.modify (_ { loading = false, result = Just response.response }) pure next

Slide 310

Slide 310 text

realkinetic.com | @real_kinetic Elm Doesn’t Support This

Slide 311

Slide 311 text

realkinetic.com | @real_kinetic All Side Effects are handled by the architecture via tasks and “effect managers”

Slide 312

Slide 312 text

realkinetic.com | @real_kinetic You likely will not need to write an effect manager (and only occasionally will you write tasks)

Slide 313

Slide 313 text

realkinetic.com | @real_kinetic Elm’s goal is to provide all necessary effect managers as part of the standard library or as provided libraries

Slide 314

Slide 314 text

realkinetic.com | @real_kinetic But if you need to write them you can

Slide 315

Slide 315 text

realkinetic.com | @real_kinetic Side Effects in Elm

Slide 316

Slide 316 text

realkinetic.com | @real_kinetic Elm uses commands for side effects

Slide 317

Slide 317 text

realkinetic.com | @real_kinetic You trigger a command which will then trigger actions as part of it’s effects

Slide 318

Slide 318 text

realkinetic.com | @real_kinetic http://elmprogramming.com/subscriptions.html

Slide 319

Slide 319 text

realkinetic.com | @real_kinetic Http http://elm-lang.org/examples/http

Slide 320

Slide 320 text

realkinetic.com | @real_kinetic Example: Making HTTP Requests (Loading gifs)

Slide 321

Slide 321 text

realkinetic.com | @real_kinetic type alias Model = { topic : String , gifUrl : String } init : (Model, Cmd Msg) init = (Model "cats" "waiting.gif", Cmd.none)

Slide 322

Slide 322 text

realkinetic.com | @real_kinetic view : Model -> Html Msg view model = div [] [ h2 [] [text model.topic] , img [src model.gifUrl] [] , button [ onClick MorePlease ] [ text "More Please!" ] ]

Slide 323

Slide 323 text

realkinetic.com | @real_kinetic type Msg = MorePlease | NewGif (Result Http.Error String) update : Msg -> Model -> (Model, Cmd Msg) update msg model = case msg of MorePlease -> (model, getRandomGif model.topic) NewGif (Ok newUrl) -> ( { model | gifUrl = newUrl }, Cmd.none) NewGif (Err _) -> (model, Cmd.none)

Slide 324

Slide 324 text

realkinetic.com | @real_kinetic getRandomGif : String -> Cmd Msg getRandomGif topic = let url = "https://api.giphy.com/v1/gifs/random?" ++ "api_key=dc6zaTOxFJmzC&tag=" ++ topic request = Http.get url decodeGifUrl in Http.send NewGif request decodeGifUrl : Decode.Decoder String decodeGifUrl = Decode.at ["data", "image_url"] Decode.string

Slide 325

Slide 325 text

realkinetic.com | @real_kinetic Http.get : String -> Decode.Decoder value -> Http.Request value Http.send : (Result Error value -> msg) -> Http.Request value -> Cmd msg —- MSG: —- NewGif (Result Http.Error String) —- UPDATE: —- NewGif (Ok newUrl) -> —- ( { model | gifUrl = newUrl }, Cmd.none)

Slide 326

Slide 326 text

realkinetic.com | @real_kinetic Time http://elm-lang.org/examples/time

Slide 327

Slide 327 text

realkinetic.com | @real_kinetic Example: “Subscribing” to Time (Making a Clock)

Slide 328

Slide 328 text

realkinetic.com | @real_kinetic main = Html.program { init = init , view = view , update = update , subscriptions = subscriptions }

Slide 329

Slide 329 text

realkinetic.com | @real_kinetic type alias Model = Time init : (Model, Cmd Msg) init = (0, Cmd.none)

Slide 330

Slide 330 text

realkinetic.com | @real_kinetic view : Model -> Html Msg view model = let angle = turns (Time.inMinutes model) handX = toString (50 + 40 * cos angle) handY = toString (50 + 40 * sin angle) in svg [ viewBox "0 0 100 100", width "300px" ] [ circle [ cx "50", cy "50", r "45", fill "#0B79CE" ] [] , line [ x1 "50", y1 "50", x2 handX, y2 handY, stroke "#023963" ] [] ]

Slide 331

Slide 331 text

realkinetic.com | @real_kinetic type Msg = Tick Time update : Msg -> Model -> (Model, Cmd Msg) update msg model = case msg of Tick newTime -> (newTime, Cmd.none)

Slide 332

Slide 332 text

realkinetic.com | @real_kinetic main = Html.program { init = init , view = view , update = update , subscriptions = subscriptions }

Slide 333

Slide 333 text

realkinetic.com | @real_kinetic import Time exposing (Time, second) subscriptions : Model -> Sub Msg subscriptions model = Time.every second Tick —- ‘Every' Type Signature every : Time -> (Time -> msg) -> Sub msg —- ‘second' Type Signature second : Time —- ‘Time’ MSG type Msg = Tick Time

Slide 334

Slide 334 text

realkinetic.com | @real_kinetic http://elmprogramming.com/subscriptions.html

Slide 335

Slide 335 text

realkinetic.com | @real_kinetic Javascript Interop

Slide 336

Slide 336 text

realkinetic.com | @real_kinetic Example: Calling into Javascript from Elm (A Spellchecker)

Slide 337

Slide 337 text

realkinetic.com | @real_kinetic This is how you inject your Elm app into your browser via Javascript …

Slide 338

Slide 338 text

realkinetic.com | @real_kinetic
var app = Elm.Spelling.fullscreen(); ### NOTE: spelling.js is the Javascript generated by the Elm compiler

Slide 339

Slide 339 text

realkinetic.com | @real_kinetic Let’s add our javascript functions

Slide 340

Slide 340 text

realkinetic.com | @real_kinetic
var app = Elm.Spelling.fullscreen(); app.ports.check.subscribe(function(word) { var suggestions = spellCheck(word); app.ports.suggestions.send(suggestions); }); fruits = [] function spellCheck(word) { // You can check on the js console if fruits // was updated by elm typing fruits fruits.push(word); return fruits; }

Slide 341

Slide 341 text

realkinetic.com | @real_kinetic main = program { init = init , view = view , update = update , subscriptions = subscriptions } type alias Model = { word : String , suggestions : List String } init : ( Model, Cmd Msg ) init = ( Model "" [], Cmd.none )

Slide 342

Slide 342 text

realkinetic.com | @real_kinetic view : Model -> Html Msg view model = div [] [ input [ onInput Change ] [] , button [ onClick Check ] [ text "Check" ] , div [] [ text (String.join ", " model.suggestions) ] ]

Slide 343

Slide 343 text

realkinetic.com | @real_kinetic type Msg = Change String | Check | Suggest (List String) update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of Change newWord -> ( Model newWord [], Cmd.none ) Check -> ( model, check model.word ) Suggest newSuggestions -> ( Model model.word newSuggestions, Cmd.none ) port check : String -> Cmd msg

Slide 344

Slide 344 text

realkinetic.com | @real_kinetic // Javascript Function app.ports.check.subscribe(function(word) { var suggestions = spellCheck(word); app.ports.suggestions.send(suggestions); }); -- Elm Wrapper port check : String -> Cmd msg

Slide 345

Slide 345 text

realkinetic.com | @real_kinetic port suggestions : (List String -> msg) -> Sub msg subscriptions : Model -> Sub Msg subscriptions model = suggestions Suggest

Slide 346

Slide 346 text

realkinetic.com | @real_kinetic app.ports.check.subscribe(function(word) { var suggestions = spellCheck(word); // Javascript Function app.ports.suggestions.send(suggestions); }); -- Elm Wrapper port suggestions : (List String -> msg) -> Sub msg

Slide 347

Slide 347 text

realkinetic.com | @real_kinetic And now you can call javascript functions as well as subscribe to javascript functions!

Slide 348

Slide 348 text

realkinetic.com | @real_kinetic Terminology

Slide 349

Slide 349 text

realkinetic.com | @real_kinetic We’ve seen functions like `map` and the concept of applying functions to data (Instead of looping through data)

Slide 350

Slide 350 text

realkinetic.com | @real_kinetic We often call data structures that can be mapped over: mappable (Look at us making up words)

Slide 351

Slide 351 text

realkinetic.com | @real_kinetic But there is precise term from mathematics to describe this concept: (Wait for it)

Slide 352

Slide 352 text

realkinetic.com | @real_kinetic Functor

Slide 353

Slide 353 text

realkinetic.com | @real_kinetic In mathematics, a functor is a type of mapping (a homomorphism) between categories arising in category theory. In the category of small categories, functors can be thought of more generally as morphisms. (https://en.wikipedia.org/wiki/Functor)

Slide 354

Slide 354 text

realkinetic.com | @real_kinetic In non category theory …

Slide 355

Slide 355 text

realkinetic.com | @real_kinetic A functor is simply something that can be mapped over.

Slide 356

Slide 356 text

realkinetic.com | @real_kinetic In Haskell and Purescript we have a “typeclass” (This is something like an “interface” or “abstract class” in other languages)

Slide 357

Slide 357 text

realkinetic.com | @real_kinetic These allows us to define rules for data structures

Slide 358

Slide 358 text

realkinetic.com | @real_kinetic class Functor f where fmap :: (a -> b) -> f a -> f b

Slide 359

Slide 359 text

realkinetic.com | @real_kinetic -- List Functor Instance instance Functor [] where fmap = map -- Maybe Functor Instance instance Functor Maybe where fmap _ Nothing = Nothing fmap f (Just a) = Just (f a) -- Either Functor Instance instance Functor (Either a) where fmap _ (Left x) = Left x fmap f (Right y) = Right (f y)

Slide 360

Slide 360 text

realkinetic.com | @real_kinetic With those classes defined you can now fmap over those structures.

Slide 361

Slide 361 text

realkinetic.com | @real_kinetic So in Haskell and Purescript when you define new structures you can implement classes for those methods as well

Slide 362

Slide 362 text

realkinetic.com | @real_kinetic Elm does not support this concept so we accomplish it a different way

Slide 363

Slide 363 text

realkinetic.com | @real_kinetic We just create the functions in the modules and use them directly

Slide 364

Slide 364 text

realkinetic.com | @real_kinetic So instead of having one `map` function that works over all structures that implement the class

Slide 365

Slide 365 text

realkinetic.com | @real_kinetic We create a function per structure: List.map Maybe.map Result.map

Slide 366

Slide 366 text

realkinetic.com | @real_kinetic Btw the next step up beyond Functor is Applicative Functor which then leads to Monads (Oh no!)

Slide 367

Slide 367 text

realkinetic.com | @real_kinetic We’re not going to dive into those today :)

Slide 368

Slide 368 text

realkinetic.com | @real_kinetic But we have been using them throughout the presentation! (Wut!)

Slide 369

Slide 369 text

realkinetic.com | @real_kinetic Let’s look at another common pattern

Slide 370

Slide 370 text

realkinetic.com | @real_kinetic We’ll start with multiplication

Slide 371

Slide 371 text

realkinetic.com | @real_kinetic When we multiply something by 1 we always get the that value back

Slide 372

Slide 372 text

realkinetic.com | @real_kinetic x * 1 == x 1 * x == x

Slide 373

Slide 373 text

realkinetic.com | @real_kinetic We have similar with addition

Slide 374

Slide 374 text

realkinetic.com | @real_kinetic x + 0 == x 0 + x == x

Slide 375

Slide 375 text

realkinetic.com | @real_kinetic A similar when combining lists

Slide 376

Slide 376 text

realkinetic.com | @real_kinetic Let x = [1,2] x ++ [] == x [] ++ x == x append x [] == x append [] x == x

Slide 377

Slide 377 text

realkinetic.com | @real_kinetic These all share the same properties

Slide 378

Slide 378 text

realkinetic.com | @real_kinetic The function takes 2 parameters

Slide 379

Slide 379 text

realkinetic.com | @real_kinetic The parameters and the returned value are the same type

Slide 380

Slide 380 text

realkinetic.com | @real_kinetic There exists a value that doesn’t change other values when used with the binary function

Slide 381

Slide 381 text

realkinetic.com | @real_kinetic And another property that we haven’t shown yet

Slide 382

Slide 382 text

realkinetic.com | @real_kinetic They are associative

Slide 383

Slide 383 text

realkinetic.com | @real_kinetic (2 + 7) + 4 == 2 + (7 + 4)

Slide 384

Slide 384 text

realkinetic.com | @real_kinetic Notice this kills things like subtraction and division

Slide 385

Slide 385 text

realkinetic.com | @real_kinetic (2 - 7) - 4 != 2 - (7 - 4) (2 / 7) / 4 != 2 / (7 / 4)

Slide 386

Slide 386 text

realkinetic.com | @real_kinetic Structures that adhere to these properties (laws) are known as:

Slide 387

Slide 387 text

realkinetic.com | @real_kinetic Monoids

Slide 388

Slide 388 text

realkinetic.com | @real_kinetic In abstract algebra, a branch of mathematics, a monoid is an algebraic structure with a single associative binary operation and an identity element. (https://en.wikipedia.org/wiki/Monoid)

Slide 389

Slide 389 text

realkinetic.com | @real_kinetic class Monoid m where mempty :: m mappend :: m -> m -> m mconcat :: [m] -> m mconcat = foldr mappend mempty

Slide 390

Slide 390 text

realkinetic.com | @real_kinetic Why do we care about Monoids?

Slide 391

Slide 391 text

realkinetic.com | @real_kinetic There are tons of reasons.

Slide 392

Slide 392 text

realkinetic.com | @real_kinetic But here is one example …

Slide 393

Slide 393 text

realkinetic.com | @real_kinetic Our hint was in the last line of the Monoid type class and we showed it earlier

Slide 394

Slide 394 text

realkinetic.com | @real_kinetic Folds

Slide 395

Slide 395 text

realkinetic.com | @real_kinetic The fold type definition: foldr :: (a -> b -> b) -> b -> [a] -> b

Slide 396

Slide 396 text

realkinetic.com | @real_kinetic For it’s arguments it requires:

Slide 397

Slide 397 text

realkinetic.com | @real_kinetic A function that takes 2 arguments

Slide 398

Slide 398 text

realkinetic.com | @real_kinetic An initial value that when applied to the binary function doesn’t change (This gives us our base case or starting point)

Slide 399

Slide 399 text

realkinetic.com | @real_kinetic And of course the item(s) we’ll apply the function to and start with the initial value

Slide 400

Slide 400 text

realkinetic.com | @real_kinetic foldr (*) 1 [1,2,3] > 6 foldr (+) 0 [2,3,4] > 9 foldr (++) [] [[1,2,3], [20, 30, 40]] > [1,2,3,20,30,40]

Slide 401

Slide 401 text

realkinetic.com | @real_kinetic This means that if we have a monoid or if we can make a structure become a monoid …

Slide 402

Slide 402 text

realkinetic.com | @real_kinetic Then we get all of this free code

Slide 403

Slide 403 text

realkinetic.com | @real_kinetic Free code that follow mathematical laws

Slide 404

Slide 404 text

realkinetic.com | @real_kinetic Which means that free code his highly unlikely to change (especially the API) and thus …

Slide 405

Slide 405 text

realkinetic.com | @real_kinetic It’s free code without many of the pains that come with dependent code and dealing with changes, versions, etc (The best and really, only kind of free code)

Slide 406

Slide 406 text

realkinetic.com | @real_kinetic This is part of the reason folks in these worlds get so excited about precise terms and laws

Slide 407

Slide 407 text

realkinetic.com | @real_kinetic These things aren’t random or context specific. They are precise.

Slide 408

Slide 408 text

realkinetic.com | @real_kinetic When you say monoid it means that it has those specific characteristics

Slide 409

Slide 409 text

realkinetic.com | @real_kinetic It can have more than those characteristics of course but at minimum it must have those to be a monoid

Slide 410

Slide 410 text

realkinetic.com | @real_kinetic From functor we get to applicative to monad and from there the ability to implement real programs

Slide 411

Slide 411 text

realkinetic.com | @real_kinetic And more keeps coming out like things like “Free” which allow us to think about the entire structure/architecture of our program

Slide 412

Slide 412 text

realkinetic.com | @real_kinetic This is why people around you this week will be super excited.

Slide 413

Slide 413 text

realkinetic.com | @real_kinetic You should dive in.

Slide 414

Slide 414 text

realkinetic.com | @real_kinetic Expose yourself to this world.

Slide 415

Slide 415 text

realkinetic.com | @real_kinetic Open your mind and expect to feel “dumb”

Slide 416

Slide 416 text

realkinetic.com | @real_kinetic It’s ok.

Slide 417

Slide 417 text

realkinetic.com | @real_kinetic We all do.

Slide 418

Slide 418 text

realkinetic.com | @real_kinetic Moving Forward

Slide 419

Slide 419 text

realkinetic.com | @real_kinetic I highly recommend you give Elm a shot

Slide 420

Slide 420 text

realkinetic.com | @real_kinetic And then give OCaml, F- Sharp, Haskell, Idris and Purescript a look.

Slide 421

Slide 421 text

realkinetic.com | @real_kinetic Especially coming from Elm I’d give Purescript a try.

Slide 422

Slide 422 text

realkinetic.com | @real_kinetic There is a great set of libraries from `rgempel` on GitHub that is a bunch of Elm’s modules implement in Purescript

Slide 423

Slide 423 text

realkinetic.com | @real_kinetic This will give you a good mapping of how the Elm concepts and terminology map into Purescript

Slide 424

Slide 424 text

realkinetic.com | @real_kinetic -- | Equivalent to Purescript's `show`. toString :: ∀ a. (Show a) => a -> String toString = show -- | Equivalent to Purescript's `<<<`. compose :: ∀ a b c. (b -> c) -> (a -> b) -> (a -> c) compose = (<<<) -- | Equivalent to Purescript's `$`. applyFn :: ∀ a b. (a -> b) -> a -> b applyFn = ($) -- | The Purescript equivalent is `id`. identity :: ∀ a. a -> a identity = id -- | The Purescript equivalent is `const`. always :: ∀ a b. a -> b -> a always = const -- | The Purescript equivalent is `Void`. type Never = Void

Slide 425

Slide 425 text

realkinetic.com | @real_kinetic And if you have or you’re already wanting more then here a few resources.

Slide 426

Slide 426 text

realkinetic.com | @real_kinetic First, if you’re going to buy a single book then buy “Haskell Programming from first principles” aka “The Haskell Book” even if you’re wanting to learn Elm

Slide 427

Slide 427 text

realkinetic.com | @real_kinetic And it’s not yet finished but Richard Feldman’s “Elm in Action” will almost certainly be one of the best resources specific to Elm

Slide 428

Slide 428 text

realkinetic.com | @real_kinetic Resources •Elm Website :: Your best resource for Elm • http://elm-lang.org/ •Elm to Purescript • https://github.com/pselm •Elm in Action • https://www.manning.com/books/elm-in-action •Haskell Programming from first principles (Haskell Book) • http://haskellbook.com/ •Type Driven Development Book • https://www.manning.com/books/type-driven-development-with-idris •PureScript Conf 2018 • June 6th … here! • https://github.com/lambdaconf/lambdaconf-2018/wiki/PureScript-Conf-2018#schedule •Elm-Conf 2018 • September 26, 2018 in St. Louis, MO as a Strange Loop pre-conference event • https://www.elm-conf.us/

Slide 429

Slide 429 text

realkinetic.com | @real_kinetic Thank you! (And please come find me if you have questions.)

Slide 430

Slide 430 text

realkinetic.com | @real_kinetic Beau Lyddon Managing Partner at Real Kinetic We mentor engineering teams to unleash your full potential. @lyddonb linkedin.com/in/beau-lyddon github.com/lyddonb