Terminology
Category Theory
Category Theory to Haskell
- Objects are types
- Morphisms are functions
- Things that take a type and return another type are type constructors
- Things that take a function and return another function are higher-order functions
- Typeclasses capture the fact that things are often defined for a ‘set’ of objects at once
Functor
A ‘container’ of some sort, along with the ability to apply a function uniformly to every element in it
Essentially a transformation between categories. Given categories and and a functor
- maps any object to (the type constructor)
- maps morphisms to (
fmap
). Importantly, this means that all functors must be generic over at least one parameter (e.g.Maybe
and notInteger
)- applying
fmap
is sometimes called ‘lifting’ as it lifts a function from the normal context into the ‘f’ world
- applying
class Functor f where
-- fmap maps morphisms
fmap :: (a -> b) -> f a -> f b
-- applies a 'constant' function to replace the values in a container
(<$) :: a -> f b -> f a
-- default implementation
(<$) = fmap . const
fmap
takes a function which maps a value from a
to b
and applies it to a Functor f
. Think of f
as the container, (a -> b)
as the function that operates on the ‘inner’ values.
Monad
Monads are functors from a category to that same category. A container for values that can be mapped over.
Think of it like a context-specific environment. You need a function to transform things outside of it to things in it. You also need a function to manipulate stuff inside of that environment.
A monad is a functor along with two morphisms
- (
return
) - (can be recovered from
bind
)
class Monad m where
-- join operation (optional, only one of bind or join need to be defined)
join :: m (m a) -> m a
-- bind operation
-- takes an f :: (a -> m b) and applies it to
-- the inner value a of m
(>>=) :: m a -> (a -> m b) -> m b
-- replaces m a with m b
(>>) :: m a -> m b -> m b
-- constructs the simplest monad m using a
return :: a -> m a
Monad laws
return a >>= k = k a
m >>= return = m
m >>= (\x -> k x >>= h) = (m >>= k) >>= h
Left and Right Associativity
Associativity of an operator determines how operators are grouped in the absence of parentheses.
For the following examples, we consider a fictional operator ~
- Associative: operations can be grouped arbitrarily (e.g. addition, order doesn’t matter)
- Left-associative: operations are grouped left to right
a ~ b ~ c
is interpreted as(a ~ b) ~ c
- Examples include
- Function application operator
- Right-associative: operations are grouped right to left
a ~ b ~ c
is interpreted asa ~ (b ~ c)
- Examples include
- Variable assignment (
=
) - Exponentiation (
^
)
- Variable assignment (
- Non-associative: operations cannot be chained
Parser Combinators
Parser combinators are a technique for implementing parsers by defining them in terms of other parsers
Notes on Chumsky
Where a
and b
are both parsers.
Parser Methods
just(a)
accepts a single stringa
a.or(b)
parsea
, ifa
fails, try parsingb
a.choice(b,c,d...)
try parsingb
,c
,d
, return first one that succeedsa.or_not()
optionally parsea
a.ignore_then(b)
ignore patterna
then parseb
a.then_ignore(b)
parsea
then ignoreb
a.then(b)
parse botha
andb
and return a tuple of(a,b)
a.padded()
ignore whitespace arounda
a.repeated().at_least(n)
parsea
at leastn
timesa.filter(fn)
only accepta
iffn(a)
evaluates to true
Result Methods
a.collect()
turn results ofa
into an iteratora.map(b)
map results ofa
into typeb
a.chain(b)
concatenate results of parsersa
andb
into collectiona.copy(b)
duplicate parser definitiona.flatten()
flatten nested collectiona.to(b)
marks result ofa
as typeb
a.labelled(b)
label result of a withb
a.end()
indicate end of parser
Haskell Syntax Quirks
$ :: (a -> b) -> a -> b
is function application (adds implicit parentheses and makes it right associative instead of left associative)- Normally,
sort "abc" ++ "def"
would be interpreted as(sort "abc") ++ "def"
- If we use the
$
operator, we can dosort $ "abc" ++ "def"
which is interpreted assort ("abc" ++ "def")
as intended.
- Normally,
.
is function composition. Read the dot as the little dot in<>
is a synonym formappend :: Monoid m => m -> m -> m
or the monoidal append<$>
is a synonym forfmap :: (a -> b) -> f a -> f b
- Intuitively like applying a function to a container
<*>
is like<$>
but for wrapped functions(<*>) :: Applicative f => f (a -> b) -> f a -> f b
- Intuitively like applying a function in a container to another container
- Remember that
(<$)
and($>)
point towards the value that will be kept void :: Functor f => f a -> f ()
is implemented asvoid x = () <$ x
. Read as: whatever you give me, I will return the unit value