-- map :: (a -> b) -> [a] -> [b]-- (+) :: Num a => a -> a -> a-- (5 +) :: Num a => a -> alistAddFive =map (5+):t listAddFive-- listAddFive :: Num b => [b] -> [b]listAddFive [1,2,3]-- [6,7,8]
Map Partially Applied
:t map-- map :: (a -> b) -> [a] -> [b]:t length-- length :: Foldable t => t a -> Int
Often you can tell exactly what the function can do from the signature alone
map :: (a -> b) -> [a] -> [b]?? :: a -> a
Product Types vs Sum Types
Collections, e.g. a & b & c: (a, b, c). Number of elements is product of number of elements of parts
Either/Or e.g. a or b. Number of elements is sum of number of elements
Most languages have product types, sum types (aka “enums”) are special
dataBool=True|False
Key Takeaway
The compiler checks certain things about types (e.g. consistency, handling all the cases of a sum type etc)
R doesn’t have sum types and we’re all the poorer for that
Defining New Types
dataTree a =Node a (Tree a) (Tree a) |Leaf aderiving (Show)mytree =Node1 (Leaf2) (Node3 (Leaf4) (Leaf5))
Generalisation of Map
map to fmap
List to Functor
:t mapmap :: (a -> b) -> [a] -> [b]:t fmapfmap ::Functor f => (a -> b) -> f a -> f b
Defining New Types
instanceFunctorTreewherefmap f (Leaf a) =Leaf (f a)fmap f (Node a l r) =Node (f a) (fmap f l) (fmap f r)fmap (5+) mytree
Key Takeaway
Layers of Abstraction lead to generalisable observations
map on lists becomes fmap on functors
Exercise: Try making a Tree data structure in R and making your own fmap for it. How easy is it to do?
Maybe
Null: the billion dollar mistake
All Nulls are the same, so encode ‘missingness’ into the type system
dataMaybe a =Nothing|Just asaferDiv ::Int->Int->MaybeFloatsaferDiv _ 0=NothingsaferDiv x y =Just (a / b) where a =fromIntegral x ::Float b =fromIntegral y ::Float
Groups
A set equipped with a binary operator, \(\cdot\)
Closure: \(\forall x, y \in C, x \cdot y \in C\)
Identity A identity element, \(e\), such that \(\forall x \in C, e \cdot x = x \cdot e = x\)
Associativity: \(\forall x, y, z \in C, x \cdot (y \cdot z) = (x \cdot y) \cdot z = x \cdot y \cdot z\)
Inverse: \(\forall x \in C, \exists x^\prime : x \cdot x^\prime = x^\prime \cdot x = e\)
Groups Monoids
A set equipped with a binary operator, \(\cdot\)
Closure: \(\forall x, y \in C, x \cdot y \in C\)
Identity A identity element, \(e\), such that \(\forall x \in C, e \cdot x = x \cdot e = x\)
Associativity: \(\forall x, y, z \in C, x \cdot (y \cdot z) = (x \cdot y) \cdot z = x \cdot y \cdot z\)
Inverse: \(\require{enclose}\enclose{horizontalstrike}{\forall x \in C, \exists x^\prime : x \cdot x^\prime = x^\prime \cdot x = e}\)
Monoids
“Squishable” or “Combinable”
e.g. Strings with string concatenations
R Vectors with c()
In Haskell, make an mempty element and mappend function, tell Haskell, and you’re done.
Abstraction getting results
What’s next
climb the ladder of abstraction: Functor, Applicative, Monad
read up on parsers
category theory?
take (pure) functional concepts and apply them to R code
Santa is trying to deliver presents in a large apartment building, but he can’t find the right floor - the directions he got are a little confusing. He starts on the ground floor (floor 0) and then follows the instructions one character at a time.
An opening parenthesis, (, means he should go up one floor, and a closing parenthesis, ), means he should go down one floor.
Advent of Code, 2015, day 1, part 1
Dfn Example
( = up a floor, ) = down a floor
“A running sum counting the floor, incrementing at each ‘(’, decrementing at each ‘)’”
{')'=⍵} '(()(()('0 0 1 0 0 1 0
{ ¯1*')'=⍵} '(()(()('1 1 ¯1 1 1 ¯1 1
{+⌿¯1*')'=⍵} '(()(()('3
Roughly equivalent to:
x <-strsplit("(()(()(", "")[[1]]purrr::reduce((-1)^as.numeric(x ==")"), `+`)