The Easy-Peasy-Lemon-Squeezy,
Sta5cally-Typed, Purely Func5onal
Programming Workshop for All!
John A. De Goes — @jdegoes
Agenda
• Func&ons
• Types, Kinds, & More Func&ons
• FP Toolbox
• OMG COFFEE BREAK!!!
• Type Classes, Effects
• Scary Sounding Things
• Let's Build a Game!
Func%onal Programming
It's all about func.ons.
Func%on Defini%on
data Food = Eggs | Coffee
data Happiness = Happy | Neutral | Unhappy
john :: Food -> Happiness
john Eggs = Unhappy
john Coffee = Happy
Func%on Applica%on
> john Eggs
Unhappy
> john Coffee
Happy
The Real Deal
1. Totality. Every element in domain must be mapped to some
element in codomain.
2. Determinism. Applying a func:on with the same value (in
domain) results in same value (in codomain).
Exercise Set 1
data CharacterStatus = Content | Hungry | Tired
describeCharacterStatus :: CharacterStatus -> String
1. Create a set called CharacterStatus, which represents the
different states of the player.
2. Create a func9on called describeCharacterStatus which
describes the state of the player.
Types
Sets of values.
Literal Types
• String : The set that contains all strings; "foo" is an element of this set.
• Number : The set that contains all numbers;0
5.5 is an element of this set.
• Int : The set that contains all integers; 3 is an element of this set.
• Char : The set that contains all characters; 'J' is an element of this set.
• Boolean : The set that contains the values true and false.
Plus records {foo: "bar"} and arrays [1, 2, 3]!
0
Not really, $%#@&!!
Product Types1
data Loc = Loc Int Int
1
They get their name from an easy way you can use to compute the size of these sets (hint: product = mul;plica;on).
Product Types
data Loc = Loc Int Int
-- |
-- |
-- |
-- The name of
-- the type.
Product Types
data Loc = Loc Int Int
-- |
-- |
-- |
-- Nonsense, please ignore!
Product Types
data Loc = Loc Int int
-- |
-- |
-- |
-- The name of a function
-- that will create values
-- of the type. AKA the
-- constructor!
Product Types
data Loc = Loc Int Int
--  /
-- /
-- Constructor parameters (types).
Product Types
data Loc = Loc Int Int
whereAmI = Loc 1 2
Product Types
What's the opposite of construc0on?4
locX :: Loc -> Int
locX (Loc x _) = x
locY :: Loc -> Int
locY (Loc _ y) = y
locX (Loc 1 2) -- 1
locY (Loc 1 2) -- 2
4
Deconstruc*on, of course! AKA pa%ern matching.
Product Types
Another way to deconstruct.
locX :: Loc -> Int
locX l = case l of
(Loc x _) -> x
Exercise Set 2
data CharacterStats = CharacterStats Int Int
startingStats :: CharacterStats
healthOf :: CharacterStats -> Int
strengthOf :: CharacterStats -> Int
1. Create a CharacterStats product type to model some character sta3s3cs in an role-playing
game (e.g. health and strength.).
2. Create some values of that type to understand how to use data constructors (startingStats).
3. Use pa@ern matching to extract individual components out of the data type (healthOf,
strengthOf).
Coproduct Types
(AKA 'Sum' Types)2
data NPC =
Ogre String Loc Number |
Wolf String Loc Number
2
They get their name from an easy way you can use to compute the size of these sets (hint: sum = addi:on).
Coproduct Types
-- The name of
-- the type
-- |
-- |
data NPC =
Ogre String Loc Number |
Wolf String Loc Number
Coproduct Types
data NPC =
Ogre String Loc Number |
Wolf String Loc Number
-- |
-- |
-- Data constructor.
Coproduct Types
data NPC =
Ogre String Loc Number |
Wolf String Loc Number
-- | | |
--  | /
--  | /
-- Constructor parameters (types).
Coproduct Types
Destruc(on / pa/ern matching.
nameOf :: NPC -> String
nameOf (Ogre name _ _) = name
nameOf (Wolf name _ _) = name
Coproduct Types
Deconstruc*on / pa/ern matching.
data NPC =
Ogre String Loc Number |
Wolf String Loc Number
nameOf :: NPC -> String
nameOf npc = case npc of
(Ogre name _ _) -> name
(Wolf name _ _) -> name
Exercise Set 3
data Monster
= Wolf CharacterStats
| Ogre CharacterStats
bigBadWolf :: CharacterStats
fearfulOgre :: CharacterStats
monsterStrength :: Monster -> Int
1. Create a Monster sum type to represent different types of monsters in a game. Make sure they share at
least one common piece of informa:on (e.g. health or name).
2. Create a few monsters of varying types (bigBadWolf, fearfulOgre).
3. Create a func:on to extract out a piece of informa:on common to all constructors (monsterStrength).
Record Types5
data NPC =
Ogre {name :: String, loc :: Loc, health :: Number} |
Wolf {name :: String, loc :: Loc, health :: Number}
5
Record types are represented using na2ve Javascript objects.
Record Types
data NPC =
Ogre {name :: String, loc :: Loc, health :: Number} |
Wolf {name :: String, loc :: Loc, health :: Number}
-- | |
-- ----------------------|---------------------/
-- |
-- Record type.
Record Types
data NPC =
Ogre {name :: String, loc :: Loc, health :: Number} |
Wolf {name :: String, loc :: Loc, health :: Number}
-- | |
-- --------------------|---------------------/
-- |
-- A 'row' of types.
Record Types
data NPC =
Ogre {name :: String, loc :: Loc, health :: Number} |
Wolf {name :: String, loc :: Loc, health :: Number}
-- |
-- A label.
Record Types
data NPC =
Ogre {name :: String, loc :: Loc, health :: Number} |
Wolf {name :: String, loc :: Loc, health :: Number}
-- |
-- The type of the label.
Record Types
Construc)on / deconstruc)on.
makeWolf :: String -> Loc -> Number -> NPC
makeWolf name loc health = Wolf {name: name, loc: loc, health: health}
nameOf :: NPC -> String
nameOf (Ogre { name : n }) = n
nameOf (Wolf { name : n }) = n
Record Types
The dot operator.
nameOf :: NPC -> String
nameOf (Ogre record) = record.name
nameOf (Wolf record) = record.name
Record Types
'Upda&ng' records.
changeName :: NPC -> NPC
changeName (Ogre r) = Ogre r { name = "Shrek" }
changeName (Wolf r) = Wolf r { name = "Big Bad" }
Record Types
Magic record syntax stuff.
(_ { name = "Shrek" }) // Function from record to updated record
record { name = _ } // Function from string to updated `record`
(_ { name = _ }) // Guess? :-)
Exercise Set 4
type State = {
playerStatus :: CharacterStatus,
playerStats :: CharacterStats }
1. Modify the State record in Game.State to add
playerStatus and playerStats (you will have to modify
initial in the Main module).
2. Modify the describe func9on in Main so it describes the
player state.
Basic Func*on Types
data Monster = Giant | Alien
data FavoriteFood = Humans | Kittens
fave :: Monster -> FavoriteFood
fave Giant = Humans
fave Alien = Kittens
Basic Func*on Types
Lambdas AKA closures AKA anonymous func3ons AKA arrow
func3ons AKA...
fave :: Monster -> FavoriteFood
fave = monster -> case monster of
Giant -> Humans
Alien -> Kittens
var fave = function(monster) {
...
}
// ECMAScript 6
var fave = monster => ...
Exercise Set 5
1. Describe the type of a func4on called defeats, which
determines if a first CharacterStats can be used to defeat a
second CharacterStats (by returning true or false).
2. Implement the func4on by using a lambda (hint: defeats =
stats1 stats2 -> ... or defeats = stats1 ->
stats2 -> ...).
Type Aliases
What's in a name?
type CharData =
{name :: String, loc :: Loc, health :: Number}
data NPC = Ogre CharData | Wolf CharData
Newtypes
Wrappers without the overhead.
newtype Health = Health Number
dead :: Health
dead = Health 0
Newtypes
Deconstruc*on / pa/ern matching.
newtype Health = Health Number
isAlive :: Health -> Boolean
isAlive (Health v) = v > 0
isAlive h = case h of
Health v -> v > 0
Exercise Set 6
1. Create newtypes for any numeric sta4s4cs in CharacterStats
(e.g. Health and Strength).
2. Create a type synonym called StatsModifier for a func4on
CharacterStats -> CharacterStats.
Higher-Order Func/ons
Or, OMG sets can hold func3ons!!!
Higher-Order Func/ons
Func%ons that accept func%ons.
likesEmptyString :: (String -> Boolean) -> Boolean
likesEmptyString f = f ""
Higher-Order Func/ons
Func%ons that return func%ons.
matches :: String -> (String -> Boolean)
matches v = text -> text == v
matchesEvil = matches "evil"
matchesEvil "john" -- false
matchesEvil "evil" -- true
Higher-Order Func/ons
"Mul%-parameter" func%ons.6
damageNpc :: Number -> (NPC -> NPC)
damageNpc damage = npc -> ...
6
Not really, of course: func/ons in PureScript are always func/ons from one set to another set.
Higher-Order Func/ons
Making sense of "mul0-parameter" func0ons: values.
f a b c d e
-- (((((f a) b) c) d) e)
Higher-Order Func/ons
Making sense of "mul0-parameter" func0ons: types.
f :: a -> b -> c -> d -> e
-- f :: (a -> (b -> (c -> (d -> e))))
Higher-Order Func/ons
MORE func*ons that return func*ons.
damageNpc :: Number -> (NPC -> NPC)
damageNpc = damage -> npc -> ...
damageNpc :: Number -> (NPC -> NPC)
damageNpc = damage npc -> ...
damageNpc :: Number -> (NPC -> NPC)
damageNpc damage = npc -> ...
damageNpc :: Number -> (NPC -> NPC)
damageNpc damage npc = ...
Exercise Set 7
boostHealth :: Int -> (CharacterStats -> CharacterStats)
boostStrength :: Int -> (CharacterStats -> CharacterStats)
1. Create a func-on boostHealth which, given an integer
amount, returns another func-on that takes stats and boosts
their health.
2. Create a func-on boostStrength which, given an integer
amount, returns another func-on that takes stats and boosts
their health.
Parametric Polymorphism
Para..what?
Polymorphic Data
Type constructors: data with "holes".
data Map4x4 a =
Map4x4 a a a a
a a a a
a a a a
a a a a
boolMap4x4 :: Map4x4 Boolean =
Map4x4 true true false true
false true true true
false false false true
true false false true
Polymorphic Data
Type-level func-ons.
-- invalid :: Map4x4 <- Not a type; a type function!
valid :: Map4x4 Boolean
The type constructor Map4x4 is a func%on whose
domain is the set of all types. Pass it a type, and it will
return a type!
Polymorphic Func/ons
Or, OMG sets can hold sets!!!
Polymorphic Func/ons
The heart of func-onal abstrac-on.
upperLeft :: forall a. Map4x4 a -> a
upperLeft v _ _ _
_ _ _ _
_ _ _ _
_ _ _ _ = v
Polymorphic Func/ons
How to read these crazy signatures.
upperLeft :: forall a. Map4x4 a -> a
-- (a :: Type) -> Map4x4 a -> a
Exercise Set 8
data Inventory a b
= LeftHand a
| RightHand b
| BothHands a b
| Empty
isEmpty :: ???
1. Create a polymorphic Inventory sum type that can represents what the
player is carrying in his or her hands.
2. Create a polymorphic func9on that determines whether or not the player is
carrying anything.
Extensible Rows
Like duck typing only be1er.
type Point r = { x :: Number, y :: Number | r }
Extensible Rows
Like duck typing only be1er.
type Point r = { x :: Number, y :: Number | r }
-- | |
-- | |
-- 'remainder' syntax that means "the rest of the row"
gimmeX :: forall r. Point r -> Number
gimmeX p = p.x
gimmeX {x: 1, y: 2, z: 3} -- 1 - works!
-- gimmeX {x: 1, z: 3} -- Invalid, no x!
Exercise Set 9
type NonPlayerCharacter = ???
type Item = ???
type PlayerCharacter = ???
getName :: ???
getName r = r.name
1. Create records for NonPlayerCharacter, Item, and
PlayerCharacter that all share at least one field (name).
2. Create a func7on that extracts a name from any record which has at
least a name field of type String.
Kinds
Categories of sets.
*
The name for the category of sets of values.
(AKA Type)
Includes things like:
• CharacterStatus
• CharacterStats
• String
* -> *
The name for the category of type-level func-ons.
(AKA Higher-Kinded Type / Type Constructor)
* -> *
data List a = Nil | Cons a (List a)
* -> *
Type constructors are just (math) func4ons!
addOne :: Number -> Number
addOne n = n + 1
result = addOne 1
List :: * -> *
data List a = Nil | Cons a (List a)
Result = List Int
* -> * -> *
Turtles all the way down.
Map :: * -> * -> *
data Map k v = ...
(* -> *) -> *
More turtles.
Container :: (* -> *) -> *
data Container f = {create :: forall a. a -> f a}
list :: Container List
list = Container {create: a -> Cons a Nil}
* -> * -> * -> * -> * -> *
Reading type constructors.
foo :: f a b c d e
-- (((((f a) b) c) d) e)
!
The name for the category of sets of effects.
foreign import data DOM :: !
# !
The name for the category of rows of effects.
-- Supply a row of effects and a type,
-- and get back another type:
foreign import data Eff :: # ! -> * -> *
trace :: forall r. String -> Eff (trace :: Trace | r) Unit
# *
The name for the category of rows of types.
-- Supply a row of types, get back another type:
foreign import data Object :: # * -> *
Foreign Types7
foreign import data jQuery :: *
7
THERE BE DRAGONZ HERE!!!
FP Toolbox
Stuff you couldn't escape even if you wanted to.
FP Toolbox
Maybe it's there, maybe it's not?8
data Maybe a = Nothing | Just a
type Player =
{ armour :: Maybe Armor }
8
AKA null, the FP way.
FP Toolbox
List: the ul+mate FP data structure.
data List a = Nil | Cons a (List a)
-- | |
-- head |
-- tail
oneTwoThree = Cons 1 (Cons 2 (Cons 3 Nil))
FP Toolbox
Either it's this or it's that.
data Either a b = Left a | Right b
type Player =
{ rightHand :: Either Weapon Shield }
FP Toolbox
Tuple, the opposite of Either.9
data Tuple a b = Tuple a b
-- | |
-- first second
I
type Player =
{ wrists :: Tuple (Maybe Bracelet) (Maybe Bracelet) }
9
AKA some)mes it's just too damn hard to name stuff!
FP Toolbox
Na#ve Javascript arrays.
[1, 2, 3] :: Array Number
Exercise Set 10
import Data.List(List(..))
data Location
= OutideCave
| InsideCave
| Plains
data Connection
= GoNorth Location Location
| GoSouth Location Location
| GoEast Location Location
| GoWest Location Location
northsouth :: Location -> Location -> List Connection
northsouth n s = Cons (GoNorth s n) (Cons (GoSouth n s) Nil)
westeast :: Location -> Location -> List Connection
westeast w e = Cons (GoWest e w) (Cons (GoEast w e) Nil)
--
-- OutsideCave -- Plains
-- |
-- |
-- InsideCave
--
gameMap :: List Connection
gameMap =
northsouth OutsideCave InsideCave ++
westeast OutsideCave Plains
1. Define a Location data type to represent all possible loca4ons in the game world.
2. Define a Connection data type to represent a connec4on (or passageway) from one loca4on to another.
3. Create a hypothe4cal gameMap (which has type List Connection), represen4ng the geography of the game world.
Type Classes
Generic interfaces, the FP way.
Type Classes
Generic interfaces in Java.
public interface Appendable<A> {
public A append(A a1, A a2);
}
class AppendableNumber extends Appendable<Float> {
public Float append(Float a1, Float a2) {
return a1 + a2;
}
}
Appendable<Float> appendableNumber = new AppendableNumber();
appendableNumber.append(1, 2); // 3!
Type Classes
Generic 'interfaces' in Javascript.
function makeAppendable(append) {
return {
append: append
};
}
var boolAppendable = makeAppendable(
function(v1, v2) {
return v1 && v2;
}
);
boolAppendable.append(true, false); // false!
Type Classes
Generic interfaces in PureScript.
class Appendable a where
append :: a -> a -> a
instance appendableNumber :: Appendable Number where
append a1 a2 = a1 + a2
append 1 2 -- 3!
Type Classes
Turbocharged polymorphism.
repeat :: forall a. (Appendable a) => Number -> a -> a
repeat 0 a = a
repeat n a = append (repeat (n - 1) a) a
sort :: forall a. (Ord a) => [a] -> [a]
-- etc.
Type Classes
Hierarchies: like OO inheritance, but not.
class Eq a where
equals :: a -> a -> Boolean
data Ordering = LT | GT | EQ
class (Eq a) <= Ord a where
compare :: a -> a -> Ordering
Type Classes
Hierarchies: like OO inheritance, but not.
class (Eq a) <= Ord a where
-- |
-- |
-- The superclass.
--
-- Read: "Ord a implies Eq a"
Exercise Set 11
class Describable a where
describe :: a -> String
examine :: a -> String
data Weapon = Sword | Spear
instance describableWeapon :: Describable Weapon where
describe :: Weapon -> String
examine :: Weapon -> String
1. Define a type class called Describable that can generate small and lengthy (String) descrip7ons of values
of some type.
2. Create a Weapon data type to denote different types of weapons.
3. Create an instance of Describable for the Weapon data type.
Effects
Or, how to get in trouble fast.
import Debug.Trace
main = trace "Hello World!"
import Debug.Trace
main = do
trace "Hello World!"
trace "Bye World!"
Exercise Set 12
1. Study the Main module to see how it uses effects to print out a
descrip7on.
Scary Sounding Things
Monadic zygohistomorphic prepromorphisms...
WTF?!?!!
Scary Sounding Things
Let's play a game: give your friend a birthday present that she'll
adore.
Scary Sounding Things
The rules of the game.
Rule 1: If something is inside a box, you may change it to anything
else and the result will s9ll be inside the box.
Rule 2: If something is not inside a box, you can pack it into a box.
Rule 3: If something is packed inside a box which is packed inside
another box, you can replace that with a single box containing that
thing.
Scary Sounding Things
Your inventory.
Item 1: You have Ripley, a Chihuaha mu2 who can magically change
a lump of coal into a beau:ful present that your friend will like.
Item 2: You have a box containing a box containing a lump of coal.
Which rules should you apply to create a birthday present your
friend will adore???
Scary Sounding Things
The rules of the game, redux.
Rule 1: If something is inside a box, you may change it to anything else and
the result will s9ll be inside the box.
(a -> b) -> f a -> f b
Rule 2: If something is not inside a box, you can pack it into a box.
a -> f a
Rule 3: If something is packed inside a box which is packed inside another
box, you can replace that with a single box containing that thing.
f (f a) -> f a
Scary Sounding Things
The rules of the game, redux redux.
fmap :: (a -> b) -> f a -> f b -- AKA (<$>)
pure :: a -> f a -- AKA return
join :: f (f a) -> f a
-- bind AKA (>>=) = fa f -> join (fmap f fa)
OMG a monad, run in terror!!!!!
Nah, just kidding
Scary sounding things give you rewrite rules
you can use to manipulate the types into the
form you require.
The scary sounding names don't
ma)er at all
Exercise Set 13
class Evitacilppa f where
erup :: forall a. a -> f a
pa :: forall a b. f (a -> b) -> f a -> f b
1. You are given f Number and Number, for some Evitacilppa f.
If you have a func7on:
add :: Number -> Number -> Number
which "rewrite rules" do you need to use so that you can apply the
add func7on to the two numbers?
Let's Finish Our Game!
Enough math already plz!!!
The Soul of an RPG
Or the types, anyway.
type Game s i = {
initial :: s,
describe :: s -> String,
parse :: String -> Either String i,
update :: s -> i -> Either String s }
runGame :: forall s i. Game s i -> Eff (game :: GAME) Unit
runGame g = ...
On Your Marks, Get Set, Go!
THANK YOU!
John A. De Goes — @jdegoes
(Do I owe you a coffee?)

The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming Workshop for All!

  • 1.
    The Easy-Peasy-Lemon-Squeezy, Sta5cally-Typed, PurelyFunc5onal Programming Workshop for All! John A. De Goes — @jdegoes
  • 2.
    Agenda • Func&ons • Types,Kinds, & More Func&ons • FP Toolbox • OMG COFFEE BREAK!!! • Type Classes, Effects • Scary Sounding Things • Let's Build a Game!
  • 3.
  • 6.
    Func%on Defini%on data Food= Eggs | Coffee data Happiness = Happy | Neutral | Unhappy john :: Food -> Happiness john Eggs = Unhappy john Coffee = Happy
  • 7.
    Func%on Applica%on > johnEggs Unhappy > john Coffee Happy
  • 8.
    The Real Deal 1.Totality. Every element in domain must be mapped to some element in codomain. 2. Determinism. Applying a func:on with the same value (in domain) results in same value (in codomain).
  • 9.
    Exercise Set 1 dataCharacterStatus = Content | Hungry | Tired describeCharacterStatus :: CharacterStatus -> String 1. Create a set called CharacterStatus, which represents the different states of the player. 2. Create a func9on called describeCharacterStatus which describes the state of the player.
  • 10.
  • 11.
    Literal Types • String: The set that contains all strings; "foo" is an element of this set. • Number : The set that contains all numbers;0 5.5 is an element of this set. • Int : The set that contains all integers; 3 is an element of this set. • Char : The set that contains all characters; 'J' is an element of this set. • Boolean : The set that contains the values true and false. Plus records {foo: "bar"} and arrays [1, 2, 3]! 0 Not really, $%#@&!!
  • 12.
    Product Types1 data Loc= Loc Int Int 1 They get their name from an easy way you can use to compute the size of these sets (hint: product = mul;plica;on).
  • 13.
    Product Types data Loc= Loc Int Int -- | -- | -- | -- The name of -- the type.
  • 14.
    Product Types data Loc= Loc Int Int -- | -- | -- | -- Nonsense, please ignore!
  • 15.
    Product Types data Loc= Loc Int int -- | -- | -- | -- The name of a function -- that will create values -- of the type. AKA the -- constructor!
  • 16.
    Product Types data Loc= Loc Int Int -- / -- / -- Constructor parameters (types).
  • 17.
    Product Types data Loc= Loc Int Int whereAmI = Loc 1 2
  • 18.
    Product Types What's theopposite of construc0on?4 locX :: Loc -> Int locX (Loc x _) = x locY :: Loc -> Int locY (Loc _ y) = y locX (Loc 1 2) -- 1 locY (Loc 1 2) -- 2 4 Deconstruc*on, of course! AKA pa%ern matching.
  • 19.
    Product Types Another wayto deconstruct. locX :: Loc -> Int locX l = case l of (Loc x _) -> x
  • 20.
    Exercise Set 2 dataCharacterStats = CharacterStats Int Int startingStats :: CharacterStats healthOf :: CharacterStats -> Int strengthOf :: CharacterStats -> Int 1. Create a CharacterStats product type to model some character sta3s3cs in an role-playing game (e.g. health and strength.). 2. Create some values of that type to understand how to use data constructors (startingStats). 3. Use pa@ern matching to extract individual components out of the data type (healthOf, strengthOf).
  • 21.
    Coproduct Types (AKA 'Sum'Types)2 data NPC = Ogre String Loc Number | Wolf String Loc Number 2 They get their name from an easy way you can use to compute the size of these sets (hint: sum = addi:on).
  • 22.
    Coproduct Types -- Thename of -- the type -- | -- | data NPC = Ogre String Loc Number | Wolf String Loc Number
  • 23.
    Coproduct Types data NPC= Ogre String Loc Number | Wolf String Loc Number -- | -- | -- Data constructor.
  • 24.
    Coproduct Types data NPC= Ogre String Loc Number | Wolf String Loc Number -- | | | -- | / -- | / -- Constructor parameters (types).
  • 25.
    Coproduct Types Destruc(on /pa/ern matching. nameOf :: NPC -> String nameOf (Ogre name _ _) = name nameOf (Wolf name _ _) = name
  • 26.
    Coproduct Types Deconstruc*on /pa/ern matching. data NPC = Ogre String Loc Number | Wolf String Loc Number nameOf :: NPC -> String nameOf npc = case npc of (Ogre name _ _) -> name (Wolf name _ _) -> name
  • 27.
    Exercise Set 3 dataMonster = Wolf CharacterStats | Ogre CharacterStats bigBadWolf :: CharacterStats fearfulOgre :: CharacterStats monsterStrength :: Monster -> Int 1. Create a Monster sum type to represent different types of monsters in a game. Make sure they share at least one common piece of informa:on (e.g. health or name). 2. Create a few monsters of varying types (bigBadWolf, fearfulOgre). 3. Create a func:on to extract out a piece of informa:on common to all constructors (monsterStrength).
  • 28.
    Record Types5 data NPC= Ogre {name :: String, loc :: Loc, health :: Number} | Wolf {name :: String, loc :: Loc, health :: Number} 5 Record types are represented using na2ve Javascript objects.
  • 29.
    Record Types data NPC= Ogre {name :: String, loc :: Loc, health :: Number} | Wolf {name :: String, loc :: Loc, health :: Number} -- | | -- ----------------------|---------------------/ -- | -- Record type.
  • 30.
    Record Types data NPC= Ogre {name :: String, loc :: Loc, health :: Number} | Wolf {name :: String, loc :: Loc, health :: Number} -- | | -- --------------------|---------------------/ -- | -- A 'row' of types.
  • 31.
    Record Types data NPC= Ogre {name :: String, loc :: Loc, health :: Number} | Wolf {name :: String, loc :: Loc, health :: Number} -- | -- A label.
  • 32.
    Record Types data NPC= Ogre {name :: String, loc :: Loc, health :: Number} | Wolf {name :: String, loc :: Loc, health :: Number} -- | -- The type of the label.
  • 33.
    Record Types Construc)on /deconstruc)on. makeWolf :: String -> Loc -> Number -> NPC makeWolf name loc health = Wolf {name: name, loc: loc, health: health} nameOf :: NPC -> String nameOf (Ogre { name : n }) = n nameOf (Wolf { name : n }) = n
  • 34.
    Record Types The dotoperator. nameOf :: NPC -> String nameOf (Ogre record) = record.name nameOf (Wolf record) = record.name
  • 35.
    Record Types 'Upda&ng' records. changeName:: NPC -> NPC changeName (Ogre r) = Ogre r { name = "Shrek" } changeName (Wolf r) = Wolf r { name = "Big Bad" }
  • 36.
    Record Types Magic recordsyntax stuff. (_ { name = "Shrek" }) // Function from record to updated record record { name = _ } // Function from string to updated `record` (_ { name = _ }) // Guess? :-)
  • 37.
    Exercise Set 4 typeState = { playerStatus :: CharacterStatus, playerStats :: CharacterStats } 1. Modify the State record in Game.State to add playerStatus and playerStats (you will have to modify initial in the Main module). 2. Modify the describe func9on in Main so it describes the player state.
  • 38.
    Basic Func*on Types dataMonster = Giant | Alien data FavoriteFood = Humans | Kittens fave :: Monster -> FavoriteFood fave Giant = Humans fave Alien = Kittens
  • 39.
    Basic Func*on Types LambdasAKA closures AKA anonymous func3ons AKA arrow func3ons AKA... fave :: Monster -> FavoriteFood fave = monster -> case monster of Giant -> Humans Alien -> Kittens var fave = function(monster) { ... } // ECMAScript 6 var fave = monster => ...
  • 40.
    Exercise Set 5 1.Describe the type of a func4on called defeats, which determines if a first CharacterStats can be used to defeat a second CharacterStats (by returning true or false). 2. Implement the func4on by using a lambda (hint: defeats = stats1 stats2 -> ... or defeats = stats1 -> stats2 -> ...).
  • 41.
    Type Aliases What's ina name? type CharData = {name :: String, loc :: Loc, health :: Number} data NPC = Ogre CharData | Wolf CharData
  • 42.
    Newtypes Wrappers without theoverhead. newtype Health = Health Number dead :: Health dead = Health 0
  • 43.
    Newtypes Deconstruc*on / pa/ernmatching. newtype Health = Health Number isAlive :: Health -> Boolean isAlive (Health v) = v > 0 isAlive h = case h of Health v -> v > 0
  • 44.
    Exercise Set 6 1.Create newtypes for any numeric sta4s4cs in CharacterStats (e.g. Health and Strength). 2. Create a type synonym called StatsModifier for a func4on CharacterStats -> CharacterStats.
  • 45.
    Higher-Order Func/ons Or, OMGsets can hold func3ons!!!
  • 46.
    Higher-Order Func/ons Func%ons thataccept func%ons. likesEmptyString :: (String -> Boolean) -> Boolean likesEmptyString f = f ""
  • 47.
    Higher-Order Func/ons Func%ons thatreturn func%ons. matches :: String -> (String -> Boolean) matches v = text -> text == v matchesEvil = matches "evil" matchesEvil "john" -- false matchesEvil "evil" -- true
  • 48.
    Higher-Order Func/ons "Mul%-parameter" func%ons.6 damageNpc:: Number -> (NPC -> NPC) damageNpc damage = npc -> ... 6 Not really, of course: func/ons in PureScript are always func/ons from one set to another set.
  • 49.
    Higher-Order Func/ons Making senseof "mul0-parameter" func0ons: values. f a b c d e -- (((((f a) b) c) d) e)
  • 50.
    Higher-Order Func/ons Making senseof "mul0-parameter" func0ons: types. f :: a -> b -> c -> d -> e -- f :: (a -> (b -> (c -> (d -> e))))
  • 51.
    Higher-Order Func/ons MORE func*onsthat return func*ons. damageNpc :: Number -> (NPC -> NPC) damageNpc = damage -> npc -> ... damageNpc :: Number -> (NPC -> NPC) damageNpc = damage npc -> ... damageNpc :: Number -> (NPC -> NPC) damageNpc damage = npc -> ... damageNpc :: Number -> (NPC -> NPC) damageNpc damage npc = ...
  • 52.
    Exercise Set 7 boostHealth:: Int -> (CharacterStats -> CharacterStats) boostStrength :: Int -> (CharacterStats -> CharacterStats) 1. Create a func-on boostHealth which, given an integer amount, returns another func-on that takes stats and boosts their health. 2. Create a func-on boostStrength which, given an integer amount, returns another func-on that takes stats and boosts their health.
  • 53.
  • 54.
    Polymorphic Data Type constructors:data with "holes". data Map4x4 a = Map4x4 a a a a a a a a a a a a a a a a boolMap4x4 :: Map4x4 Boolean = Map4x4 true true false true false true true true false false false true true false false true
  • 55.
    Polymorphic Data Type-level func-ons. --invalid :: Map4x4 <- Not a type; a type function! valid :: Map4x4 Boolean The type constructor Map4x4 is a func%on whose domain is the set of all types. Pass it a type, and it will return a type!
  • 56.
    Polymorphic Func/ons Or, OMGsets can hold sets!!!
  • 57.
    Polymorphic Func/ons The heartof func-onal abstrac-on. upperLeft :: forall a. Map4x4 a -> a upperLeft v _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ = v
  • 58.
    Polymorphic Func/ons How toread these crazy signatures. upperLeft :: forall a. Map4x4 a -> a -- (a :: Type) -> Map4x4 a -> a
  • 59.
    Exercise Set 8 dataInventory a b = LeftHand a | RightHand b | BothHands a b | Empty isEmpty :: ??? 1. Create a polymorphic Inventory sum type that can represents what the player is carrying in his or her hands. 2. Create a polymorphic func9on that determines whether or not the player is carrying anything.
  • 60.
    Extensible Rows Like ducktyping only be1er. type Point r = { x :: Number, y :: Number | r }
  • 61.
    Extensible Rows Like ducktyping only be1er. type Point r = { x :: Number, y :: Number | r } -- | | -- | | -- 'remainder' syntax that means "the rest of the row" gimmeX :: forall r. Point r -> Number gimmeX p = p.x gimmeX {x: 1, y: 2, z: 3} -- 1 - works! -- gimmeX {x: 1, z: 3} -- Invalid, no x!
  • 62.
    Exercise Set 9 typeNonPlayerCharacter = ??? type Item = ??? type PlayerCharacter = ??? getName :: ??? getName r = r.name 1. Create records for NonPlayerCharacter, Item, and PlayerCharacter that all share at least one field (name). 2. Create a func7on that extracts a name from any record which has at least a name field of type String.
  • 63.
  • 64.
    * The name forthe category of sets of values. (AKA Type) Includes things like: • CharacterStatus • CharacterStats • String
  • 65.
    * -> * Thename for the category of type-level func-ons. (AKA Higher-Kinded Type / Type Constructor)
  • 66.
    * -> * dataList a = Nil | Cons a (List a)
  • 67.
    * -> * Typeconstructors are just (math) func4ons! addOne :: Number -> Number addOne n = n + 1 result = addOne 1 List :: * -> * data List a = Nil | Cons a (List a) Result = List Int
  • 68.
    * -> *-> * Turtles all the way down. Map :: * -> * -> * data Map k v = ...
  • 69.
    (* -> *)-> * More turtles. Container :: (* -> *) -> * data Container f = {create :: forall a. a -> f a} list :: Container List list = Container {create: a -> Cons a Nil}
  • 70.
    * -> *-> * -> * -> * -> * Reading type constructors. foo :: f a b c d e -- (((((f a) b) c) d) e)
  • 71.
    ! The name forthe category of sets of effects. foreign import data DOM :: !
  • 72.
    # ! The namefor the category of rows of effects. -- Supply a row of effects and a type, -- and get back another type: foreign import data Eff :: # ! -> * -> * trace :: forall r. String -> Eff (trace :: Trace | r) Unit
  • 73.
    # * The namefor the category of rows of types. -- Supply a row of types, get back another type: foreign import data Object :: # * -> *
  • 74.
    Foreign Types7 foreign importdata jQuery :: * 7 THERE BE DRAGONZ HERE!!!
  • 75.
    FP Toolbox Stuff youcouldn't escape even if you wanted to.
  • 76.
    FP Toolbox Maybe it'sthere, maybe it's not?8 data Maybe a = Nothing | Just a type Player = { armour :: Maybe Armor } 8 AKA null, the FP way.
  • 77.
    FP Toolbox List: theul+mate FP data structure. data List a = Nil | Cons a (List a) -- | | -- head | -- tail oneTwoThree = Cons 1 (Cons 2 (Cons 3 Nil))
  • 78.
    FP Toolbox Either it'sthis or it's that. data Either a b = Left a | Right b type Player = { rightHand :: Either Weapon Shield }
  • 79.
    FP Toolbox Tuple, theopposite of Either.9 data Tuple a b = Tuple a b -- | | -- first second I type Player = { wrists :: Tuple (Maybe Bracelet) (Maybe Bracelet) } 9 AKA some)mes it's just too damn hard to name stuff!
  • 80.
    FP Toolbox Na#ve Javascriptarrays. [1, 2, 3] :: Array Number
  • 81.
    Exercise Set 10 importData.List(List(..)) data Location = OutideCave | InsideCave | Plains data Connection = GoNorth Location Location | GoSouth Location Location | GoEast Location Location | GoWest Location Location northsouth :: Location -> Location -> List Connection northsouth n s = Cons (GoNorth s n) (Cons (GoSouth n s) Nil) westeast :: Location -> Location -> List Connection westeast w e = Cons (GoWest e w) (Cons (GoEast w e) Nil) -- -- OutsideCave -- Plains -- | -- | -- InsideCave -- gameMap :: List Connection gameMap = northsouth OutsideCave InsideCave ++ westeast OutsideCave Plains 1. Define a Location data type to represent all possible loca4ons in the game world. 2. Define a Connection data type to represent a connec4on (or passageway) from one loca4on to another. 3. Create a hypothe4cal gameMap (which has type List Connection), represen4ng the geography of the game world.
  • 82.
  • 83.
    Type Classes Generic interfacesin Java. public interface Appendable<A> { public A append(A a1, A a2); } class AppendableNumber extends Appendable<Float> { public Float append(Float a1, Float a2) { return a1 + a2; } } Appendable<Float> appendableNumber = new AppendableNumber(); appendableNumber.append(1, 2); // 3!
  • 84.
    Type Classes Generic 'interfaces'in Javascript. function makeAppendable(append) { return { append: append }; } var boolAppendable = makeAppendable( function(v1, v2) { return v1 && v2; } ); boolAppendable.append(true, false); // false!
  • 85.
    Type Classes Generic interfacesin PureScript. class Appendable a where append :: a -> a -> a instance appendableNumber :: Appendable Number where append a1 a2 = a1 + a2 append 1 2 -- 3!
  • 86.
    Type Classes Turbocharged polymorphism. repeat:: forall a. (Appendable a) => Number -> a -> a repeat 0 a = a repeat n a = append (repeat (n - 1) a) a sort :: forall a. (Ord a) => [a] -> [a] -- etc.
  • 87.
    Type Classes Hierarchies: likeOO inheritance, but not. class Eq a where equals :: a -> a -> Boolean data Ordering = LT | GT | EQ class (Eq a) <= Ord a where compare :: a -> a -> Ordering
  • 88.
    Type Classes Hierarchies: likeOO inheritance, but not. class (Eq a) <= Ord a where -- | -- | -- The superclass. -- -- Read: "Ord a implies Eq a"
  • 89.
    Exercise Set 11 classDescribable a where describe :: a -> String examine :: a -> String data Weapon = Sword | Spear instance describableWeapon :: Describable Weapon where describe :: Weapon -> String examine :: Weapon -> String 1. Define a type class called Describable that can generate small and lengthy (String) descrip7ons of values of some type. 2. Create a Weapon data type to denote different types of weapons. 3. Create an instance of Describable for the Weapon data type.
  • 90.
    Effects Or, how toget in trouble fast.
  • 91.
    import Debug.Trace main =trace "Hello World!"
  • 92.
    import Debug.Trace main =do trace "Hello World!" trace "Bye World!"
  • 93.
    Exercise Set 12 1.Study the Main module to see how it uses effects to print out a descrip7on.
  • 94.
    Scary Sounding Things Monadiczygohistomorphic prepromorphisms... WTF?!?!!
  • 95.
    Scary Sounding Things Let'splay a game: give your friend a birthday present that she'll adore.
  • 96.
    Scary Sounding Things Therules of the game. Rule 1: If something is inside a box, you may change it to anything else and the result will s9ll be inside the box. Rule 2: If something is not inside a box, you can pack it into a box. Rule 3: If something is packed inside a box which is packed inside another box, you can replace that with a single box containing that thing.
  • 97.
    Scary Sounding Things Yourinventory. Item 1: You have Ripley, a Chihuaha mu2 who can magically change a lump of coal into a beau:ful present that your friend will like. Item 2: You have a box containing a box containing a lump of coal. Which rules should you apply to create a birthday present your friend will adore???
  • 98.
    Scary Sounding Things Therules of the game, redux. Rule 1: If something is inside a box, you may change it to anything else and the result will s9ll be inside the box. (a -> b) -> f a -> f b Rule 2: If something is not inside a box, you can pack it into a box. a -> f a Rule 3: If something is packed inside a box which is packed inside another box, you can replace that with a single box containing that thing. f (f a) -> f a
  • 99.
    Scary Sounding Things Therules of the game, redux redux. fmap :: (a -> b) -> f a -> f b -- AKA (<$>) pure :: a -> f a -- AKA return join :: f (f a) -> f a -- bind AKA (>>=) = fa f -> join (fmap f fa)
  • 100.
    OMG a monad,run in terror!!!!!
  • 101.
    Nah, just kidding Scarysounding things give you rewrite rules you can use to manipulate the types into the form you require.
  • 102.
    The scary soundingnames don't ma)er at all
  • 103.
    Exercise Set 13 classEvitacilppa f where erup :: forall a. a -> f a pa :: forall a b. f (a -> b) -> f a -> f b 1. You are given f Number and Number, for some Evitacilppa f. If you have a func7on: add :: Number -> Number -> Number which "rewrite rules" do you need to use so that you can apply the add func7on to the two numbers?
  • 104.
    Let's Finish OurGame! Enough math already plz!!!
  • 105.
    The Soul ofan RPG Or the types, anyway. type Game s i = { initial :: s, describe :: s -> String, parse :: String -> Either String i, update :: s -> i -> Either String s } runGame :: forall s i. Game s i -> Eff (game :: GAME) Unit runGame g = ...
  • 106.
    On Your Marks,Get Set, Go!
  • 107.
    THANK YOU! John A.De Goes — @jdegoes (Do I owe you a coffee?)