AdRoll Tech Talk Presentation:
In this talk I present three approaches to understanding monads:
- How Monads Arise Naturally
- Monads as Implemented in Haskell
- Monads in Category Theory
2. Three Approaches
I. How Monads Arise.
(Ref: You Could Have Invented Monads)
I. Monads in Haskell
(Ref: Real World Haskell)
I. Monads in Category Theory
(Ref: Wikibooks - Haskell/Category Theory)
4. In a typed language consider
f,g : Float -> Float
and their composition
g . f : Float -> Float
Example (A)
5. What if we want debugging information?
f : Float -> (Float, String)
f(x) = (2*x, “Doubled!”)
g : Float -> (Float, String)
g(x) = (x/4, “Quartered!”)
6. Now we can’t compose them. Yet there is an
obvious “composition”:
x |-> ((2*x)/4, “Doubled! Quartered!”)
7. Example (B)
Consider multi-valued functions
f : Advertisable -> [Campaign]
g : Campaign -> [Ad]
We can’t compose them but there is a natural
“composition”
8. (In Python)
adv |-> [g(camp) for camp in f(adv)]
But this gets ugly for multiple compositions...
9. Example (C)
Consider functions with possible failure
f : Logline -> TimeStamp (Not in Logline?)
g : TimeStamp -> DayOfWeek (Parsing fails?)
10. We can add a Bool to indicate success
f : Logline -> (TimeStamp, Bool)
g : TimeStamp -> (DayOfWeek, Bool)
We can no longer compose them but there is
again a natural “composition” (propagate
failure)
11. These three examples are similar.
Each involves a “decorated type”
(A) (Float, String) for Float
(B) [Campaign] for Campaign
(C) (TimeStamp, Bool) for TimeStamp
12. For each example, we first define two functions,
unit and bind.
unit -- maps basic type to decorated type
bind -- “upgrades” function which takes basic
type to instead take decorated type
23. Points
bind gives us the desired composition!
Instead of g.f do (bind g).f
unit can be used to start the chain.
Instead of g.f do (bind g).(bind f).unit
24. Points
bind gives us the desired composition!
Instead of g.f do (bind g).f
unit can be used to start the chain.
Instead of g.f do (bind g).(bind f).unit
unit/bind depend only on the “type extension”.
e.g. there is a unit/bind for List not List-of-Strings.
28. Haskell
Strongly/Statically typed
(cannot even add Integer and Float!)
Pure functional language
(absolutely no side effects. I/O must be handled specially)
There’s a type for that
(where other languages use enums/structs/classes, Haskell uses types)
30. Type Synonyms: (type)
type TimeStamp = String
type Advertisable = String
type Campaign = String
Syntactic sugar for existing types. In fact
type String = [Char]
31. New Data Types: (data)
type Name = String
type Age = Int
data Customer = Customer Name Age
“type constructor” “value constructor”
32. Algebraic Data Types:
data Bool = True | False
data Color = Red | Blue | Green
data LineType = Impression
|Click
|Win
|Bid
value constructors
33. More Algebraic Data Types:
type CPM = Float
type VCPC = Float
type ClickProb = Float
data PricingStrategy = FixedBid CPM
|BidIQ VCPC
bid_price :: PricingStrategy -> ClickProb -> CPM
bid_price strat p = case strat of
FixedBid cpm -> cpm
BidIQ vcpc -> vcpc * p
34. Parameterized Types:
data Maybe a = Just a | Nothing
data List a = Cons a (List a) | Nil
data Tree a = Node a (Tree a) (Tree a)
|Empty
Then can use Maybe String or List Float
36. Example: The Show Typeclass
class Show a where
show :: a -> String
data LineType = Impression | Click | Win
instance Show LineType where
show Impression = “imp”
show Click = “cli”
show Win = “win”
37. In fact the Haskell REPL uses show to display results!
38. Example: The Eq Typeclass
class Eq a where
(==),(/=) :: a -> a -> Bool
x == y = not (x /= y)
x /= y = not (x == y)
Only need to define one, the other
comes free!
42. Monads in Haskell are just a typeclass
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b (bind)
return :: a -> m a (unit)
...which a parameterized type can implement!
50. Example (C) -- The Maybe Monad
instance Monad Maybe where
return x = Just x
(Just x) >>= f = f x
Nothing >>= f = Nothing
(This is in the Haskell Prelude)
51.
52.
53. Example (A) -- The History Monad
data History a = History a String
instance Monad History where
return x = History x “”
(History x old) >>= f = let (History y new) = f x
in History y (old ++ new)
-- Implementation of Show omitted --
(Not in Prelude -- this is our creation)
54.
55.
56. Bonus Monad -- IO Monad
I/O in Haskell is handled via the IO Monad.
e.g. Haskell’s “print” is
putStrLn :: String -> IO ()
57.
58. Part II Takeaways
In Haskell, a Monad is just a typeclass
... which a parametric type can implement by
implementing return and (>>=).
Basic I/O in Haskell uses the IO Monad.
do syntactic sugar emulates imperative code.
60. Category Theory
A category is a collection of
objects
arrows/morphisms between pairs of objects
notion of composition of arrows
satisfying
(Associativity) h.(g.f) = (h.g).f
(Identity) id . f = f , g . id = g
61. Ex: Set (Category of Sets)
Objects: Sets
Arrows: Functions between sets
Note: Set contains all sets and all
functions between sets in the universe!
63. Ex: Hask (Category of Haskell Types)
Objects: Haskell types
Arrows: Haskell functions
Note: Hask contains all types and all
functions in the universe!
65. Functors
A functor is a mapping F between categories C and D.
Maps each object X in C to F(X) in D
Maps each arrow f : X -> Y to F(f) : F(X) -> F(Y)
satisfying
F(id) = id
F(g . f)=F(g) . F(f)
66. Ex: Powerset Functor P : Set -> Set
Maps each set (object) to its power set
e.g. P({1,2}) = { ϕ , {1}, {2}, {1,2} }
Maps arrow f : X -> Y to P(f) : P(X) -> P(Y) by
[F(f)](S) = { f(s) | s in S}
(exercise: check that functor conditions are satisfied)
67. Monads
A monad is a functor M : C -> C along with two mappings
for every object X in C.
unit : X -> M(X)
join : M(M(X)) -> M(X)
such that unit and join satisfy certain properties (“monad
laws”)...
68. Monad Laws
1.join . M(join) = join . join
2.join . M(unit) = join . unit = id
3.unit . f = M(f) . unit
4.join . M(M(f)) = M(f) . join
70. Ex: Powerset Functor is a Monad
where
unit : X -> P(X)
unit(x) = {x}
join : P(P(X)) -> P(X)
71. Ex: Powerset Functor is a Monad
where
unit : X -> P(X)
unit(x) = {x}
join : P(P(X)) -> P(X)
join(S) = U
s in S
s
72. Check Monad Laws (We’ll just check #3 here)
3) unit . f = P(f) . unit
Consider f : {1, 2} -> {3, 4, 5}
1 |-> 3, 2 |-> 5
(unit . f)(1) = unit(f(1)) = unit(3) = {3}
(P(f).unit)(1) = [P(f)](unit(1)) = [P(f)]({1}) = {3}
same!
73. Back to Hask
[ ] is a functor from Hask to Hask.
● Maps objects:
● Maps functions:
74. Back to Hask
[ ] is a functor from Hask to Hask.
● Maps objects:
Maps type to list of that type
● Maps functions:
75. Back to Hask
[ ] is a functor from Hask to Hask.
● Maps objects:
Maps type to list of that type
● Maps functions:
e.g. maps function f : String -> Float to [ ](f): [String] -> [Float]
by [ ](f) = map f
76. In fact, [ ] is a monad from Hask to Hask.
unit : X -> [X]
join : [[X]] -> [X]
77. In fact, [ ] is a monad from Hask to Hask.
unit : X -> [X]
x |-> [x]
join : [[X]] -> [X]
78. In fact, [ ] is a monad from Hask to Hask.
unit : X -> [X]
x |-> [x]
join : [[X]] -> [X]
list_of_lists |-> concat list_of_lists
79. In fact, [ ] is a monad from Hask to Hask.
unit : X -> [X]
x |-> [x]
join : [[X]] -> [X]
list_of_lists |-> concat list_of_lists
(Exercise: Check the monad laws)
80. Maybe is a functor from Hask to Hask.
● Maps objects:
● Maps functions:
81. Maybe is a functor from Hask to Hask.
● Maps objects:
e.g. maps String to Maybe String
● Maps functions:
82. Maybe is a functor from Hask to Hask.
● Maps objects:
e.g. maps String to Maybe String
● Maps functions:
given f : X -> Y
define Maybe f : Maybe X -> Maybe Y
Just x |-> Just (f x)
Nothing |-> Nothing
83. In fact, Maybe is a monad from Hask to Hask.
unit : X -> Maybe X
join : Maybe (Maybe X) -> Maybe X
84. In fact, Maybe is a monad from Hask to Hask.
unit : X -> Maybe X
x |-> Just x
join : Maybe (Maybe X) -> Maybe X
85. In fact, Maybe is a monad from Hask to Hask.
unit : X -> Maybe X
x |-> Just x
join : Maybe (Maybe X) -> Maybe X
Just (Just x) |-> Just x
Just Nothing |-> Nothing
Nothing |-> Nothing
86. In fact, Maybe is a monad from Hask to Hask.
unit : X -> Maybe X
x |-> Just x
join : Maybe (Maybe X) -> Maybe X
Just (Just x) |-> Just x
Just Nothing |-> Nothing
Nothing |-> Nothing
(Exercise: Check the monad laws)
87. Wait… definitions seem different?
Part II (Haskell):
Monad is a typeclass
and you define
unit/return
bind/(>>=)
Part III (Categories):
Monad is a functor
and you define
how it maps functions
unit
join
and check monad laws!
88. Answers
● Haskell Monad is just a programming construct
○ Doesn’t require monad laws to compile
○Typeclass could have a different name
89. Answers
● Haskell Monad is just a programming construct
○ Doesn’t require monad laws to compile
○Typeclass could have a different name
● Haskell also has a typeclass Functor
○ Implements fmap
○But Monad instance need not be Functor instance
90. Answers
● return, (>>=) are equivalent to unit, join, fmap by
unit = return
join x = x >>= id
fmap f x = x >>=(return.f)
return = unit
x >>= f = join(fmap f x)
92. Bibliography
Piponi, Dan “You Could Have Invented Monads!”
http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html.
August, 2006. Accessed June, 2015.
O’Sullivan, B., Stewart, D., Goerzen, J. Real World Haskell.
O’Reilly Media, 2008. Print.
https://en.wikibooks.org/wiki/Haskell/Category_theory