The Typeclassopedia - A summary
This is a summary of Brent Yorgey's excellent article "The Typeclassopedia", originally published in issue #13 of "The Monad Reader".
Table of Contents
1 Functor
- "container" with ability to apply a function to every element
fmapapplies function to each element of the container without altering the structure of the container
- a functor represents some sort of "computational context"
fmapapplies function without altering context
- example: a list and the
mapfunction
- exported by the
Prelude
- instances
[]
Maybe
Either e
IO
Tree
Map
Sequence
Stream
Setis NOT a functor in Haskell because of theOrdtype constraint
- laws
fmap id = id
mapping the identity has no effect
fmap (g . h) = fmap g . fmap h
mapping a function composition has the same effect as first mapping one and then the other function
fmap :: Functor f => (a -> b) -> f a -> f b
fmap :: (a -> b) -> (f a -> f b)the extra parenthesis show thatfmaptransforms a "normal" function into one operating on containers/contexts => "lift"
2 Pointed
- not in the standard libraries, but in
category-extras
- represents pointed functors
- useful for understanding
ApplicativeandMonad
- Pointed represents additional ability for putting value in default context
- defines a
purefunction aka singleton, return, unit, point
for exampleJustforMaybe
- most standard
Functorinstances could be instances ofPointed
- law
fmap g . pure = pure . g
- impossible to write an instance that does not satisfy it
3 Applicative
- defined in
Control.Applicative
- newer addition to standard Haskell type classes
- applicative functors are exactly in between
FunctorandMonad
- every
Applicativeinstance must also be aFunctor
- adds one capability to
Pointed, applying a function which itself is in a context
<*>is basically just function application within a context
- laws
fmap g x = pure g <*> x
g <$> x = pure g <*> xmapping a function
gover a contextxis the same as injectingginto the context withpureand then applying it toxwith<*>
- other laws relate to
pure
- instances
- most instances of
Functor
Consttype constructor (defined inApplicative)
WrappedMonadandWrappedArrownewtypes
- most instances of
4 Monad
- special because Haskell made them framework for I/O operations
- special because of syntactic sugar (do-notation)
- older than
ApplicativeandArrow
- exported by the
Prelude, many utility functions inControl.Monad
- additional instances in
Control.Monad.Instances
- methods
returnis the same aspure
(>>)comes with a default implementation
failis a hack with no place in theMonadclass
(>>=)akabindmakesMonadmore powerful thanApplicative
(>>=)combines 2 computations into 1 larger computation
- structure of a monadic computation can change depending on intermediate values; more powerful than
Applicativewhere structure is fixed
- instances
Identity
Maybemodels computations which may fail
[]similar toApplicative, models non-deterministic computations
IOimplemented in compiler specific ways; allows to build up values representing possibly effectful computations
((->) e)aka "reader monad" for computations with a read-only environmente(seeControl.Monad.Reader)
Writer(defined inControl.Monad.Writer) collects information as computation progresses
State(Control.Monad.State) representes stateful computations
Cont(Control.Monad.Cont) models computations in CPS; has been called the "mother of all monads"
- utility functions
joinremoves one level of monadic structure
liftMis likefmap
apis equivalent to<*>
sequencecombines list of computations into one which collects a list of their results
replicateMis a combination ofreplicateandsequence
mapMmaps first argument over second and sequences results
(=<<)is(>>=)with reversed arguments
(>=>)is like function composition but with an extramon the result type of the functions and swapped arguments
- many of the above function have underscore variants (like
mapM_that are only used for side-effects and throw away the results of the computations)
- laws
return a >>= k = k a(injecting and binding is the same as applying)
m >>= return = m(binding and returning leavesmunchanged)
m >>= (\x -> kx >>= h) = (m >>= k) >>= h((>>=)is sort of associative)
fmap f xs = xs >>= return . f = liftM f xs(ensures thatfmapandliftMare the same for types which are instances ofFunctorandMonad)
- alternative laws using
(>=>)
return >=> g = g(returnis the identity of(>=>))
g >=> return = g(same as above)
(g >=> h) >=> k = g >=> (h >=> k)((>=>)is associative)
- do-notation
- syntatactic sugar for "imperative style" programming
- do-blocks are recursively translated into monad operations
- plays strongly on "computational context" interpretation rather than "container" interpretation
- syntatactic sugar for "imperative style" programming
- monad transformers
- used for combining monads into a new monad
State,ReaderT,ErrorTand (soon)MaybeT
- build composite monads "inside out" (see lambdabot's
@unmtlcommand)
- all monad transformers implement the
MonadTranstypeclass (Control.Monad.Trans)
- used for combining monads into a new monad
MonadFix
- describes monads which support the fixpoint operation
mfix
mfix :: (a -> m a) -> m a: allows output of monadic computation to be defined via recursion
mdois a "recursive do" notation
- describes monads which support the fixpoint operation
5 Monoid
- a set
Swith an associative binary operation⊕and an identity element in respect to that operation
- examples:
- natural numbers under addition
- integers under multiplication
- boolean values under conjuction and disjunction
- natural numbers under addition
- defines several functions
memptyis the identity element
mappendis the binary operation
mconcat's default implementations foldsmappend, usually sufficient
- laws
mempty `mappend` x = x
x `mappend` mempty = x
(x `mappend` y) `mappend` z = x `mappend` (y `mappend` z)
- instances
- defined in
Data.Monoid
[a], withmempty = []andmappend = (++)
SumandProductnewtype wrappers for numeric types under addition/multiplication
AnyandAllas newtype wrappers forBoolunder disjunction and conjunction
Maybe, as well asFirstandLast
Endo a, newtype wrapper foa -> a, which form a monoid under composition
Ordering = LT | EQ | GTwithmempty = EQandmconcat (zipWith compare xs ys)
- instances for container types
- defined in
- other monoidial classes
AlternativeforApplicativefunctors with monoid structure
MonadPlusfor monads with a monoid structure (monads which support "choice and failure")
ArrowZeroandArrowPlusfor representingArrowswith monoid structure
6 Foldable
- defined in
Data.Foldable
- for containers that can be "folded" into a summary value
- container-agnostic
- to make an instance either implement
foldMaporfoldr
foldMap :: Monoid m => (a -> m) -> t a -> m
foldr :: (a -> b -> b) -> b -> t a -> b
- instances
List
Maybe
Array
- containers like
Map,Set,Tree
- module contains generalized versions of
Preludefunctions likeconcat,any,alletc.
- generic functions to work with
ApplicativeorMonadinstances liketraverse_,sequenceA_etc.
Foldableoperations forget structure of container type, butTraversablewill preserve it
7 Traversable
- defined in
Data.Traversable
- every
Traversableis a foldable functor
- instances only need to implement
traverseandsequenceA
sequenceAis the key method ofTraversable
sequenceA :: Applicative f => t (f a) -> f (t a)
- answers the question when we can commute two functors
- ability to compose two mondas depends crucially on this
- instances
[]
Maybe
Map
Tree
Sequence
Setis notTraversableeven though it'sFoldable
TraversableandFunctorinstances are almost identical, butTraversabletakes place within anApplicativecontext
- any
Traversablefunctor is alsoFoldableand aFunctor, both classes can be implemented only with methods fromTraversable
8 Category
- fairly new addition to Haskell standard library
- generalizes notion of function compositions to general "morphisms"
- defined in
Control.Category
- instance of
Categoryshould be something of kind* -> * -> *(a type constructor which takes 2 type arguments)
- instances
(->)
Kleisli
- methods
id :: cat a a
(.) :: cat b c -> cat a b -> cat a c
- law
idand(.)should form a monoid (idshould be identity of(.)and(.)should be associative)
- two additional operators
(<<<), a synonym for(.)
(>>>), is(.)with its arguments reversed
- can only represent categories whose objects are objects of
Hask, more general category treatment incategory-extras
9 Arrow
- another abstraction of computation, like
MonadandApplicative
- type of an
Arrowcomputation reflects both its input and output
Arrowsgeneralize functions, may represent some sort of "effectful" computation
Categoryclass constraint, so we get identity arrows and arrow composition for free
- methods that need to be implement
arr :: (b -> c) -> (b ~> c): takes any functionb -> cand turns it into a generalized arrowb ~> c. Says we can treat any function as an arrow.
first :: (b ~> c) -> ((b, d) ~> (c, d)): turns any arrow frombtocinto an arrow from(b,d)to(c,d). Processes first element of a tuple while leaving the second one unchanged
- further methods
second :: (b ~> c) -> ((d, b) ~> (d, c)): similar tofirst, but with elements of tuple swapped
(***) :: (b ~> c) -> (b’ ~> c’) -> ((b, b’) ~> (c, c’)): "parallel composition" of arrows; takes two arrows and turns them into one on tuples (first arrow on first element, second arrow on second element)
(&&&) :: (b ~> c) -> (b ~> c’) -> (b ~> (c, c’)): "fanout composition"; takes two arrows and makes them into a new arrow which supplies its input to both arrows, returning their results as a tuple
- instances
- only two instances in library
(->), the normal function constructor
Kleisli mwhich makes functions of typea -> m bintoArrowsfor anyMonad m
- only two instances in library
- laws
arr id = id
arr (h . g) = arr g >>> arr h
first (arr g) = arr (g *** id)
first (g >>> h) = first g >>> first h
first g >>> arr (id ***h ) = arr (id *** h) >>> first g
first g >>> arr fst = arr fst >>> g
first (first g) >>> arr assoc = arr assoc >>> first g
assoc ((x,y),z) = (x,(y,z))
10 ArrowChoice
- allows for alternate execution paths based on intermediate results
- methods
left :: (b ~> c) -> (Either b d ~> Either c d)
right :: (b ~> c) -> (Either d b ~> Either d c)
(+++) :: (b ~> c) -> (b’ ~> c’) -> (Either b b’ ~> Either c c')
(|||) :: (b ~> d) -> (c ~> d) -> (Either b c ~> d)
- similar to
first,second,(***)and(&&&), but operating on sum types instead of product types (tuples)
- operate on arrows whose inputs are tagged with
LeftandRightand choose how to act based on that
left ghas the behavior ofgfor inputs tagged withLeftand behaves as the identity for inputs tagged asRight
right gis the mirror image ofleft
(***)performs "multiplexing":gbehaves asgfor inputs tagged asLeftandhbehaves ashfor inputs tagged asRight; tags are preserved
(|||)is "merge" or "fanin": like(***)but tags are discarded; mnemonic:g ||| hperforms eithergorh.
11 ArrowApply
- more flexible than
ArrowChoice
- can compute an arrow from intermediate results and this computed arrow continues the computation
- method
app :: (b ~> c, b) ~> c
- allows us to apply a computed arrow to an input
- this is exactly what monadic bin (
(>>=)) does
ArrowApplyandMonadare equivalent in expressive power
- any instance of
ArrowApplycan be made aMonadviaArrowMonad
12 ArrowLoop
- describes arrows that can use recursion to compute results
- used to desugar
recconstruct in arrow notation
- GHC has a special arrow notation similar to do-notation that allows to assign names to intermediate results
13 Comonad
- categorical dual of
Monad
extractis the dual ofreturn
duplicateis the dual ofjoin(adds layer of monadic wrapping)
extendis the dual of(>>=)with arguments in different order
- can be defined by
fmap,extractand eitherduplicateorextend
