Arnaud Spiwack
Data
Control
Data.Functor
Data.Traversable
Control.Applicative
Control.Monad
Data.Functor
Data.Traversable
“traverse is always the answer” is funny because of how surprisingly often that is true! — Matt Parsons
fmap :: (a -> b) -> t a -> t btraverse
:: Applicative f => (a -> f b) -> t a -> f (t b)Examples:
[a]Map Int aData
Control
Data.Functor
Data.Traversable
Control.Applicative
Control.Monad
fmaptraverseControl.Applicative
Control.Monad
pure :: a -> m a
(<*>) :: m (a -> b) -> m a -> m breturn :: a -> m a
(>>=) :: m a -> (a -> m b) -> m bdo
a <- tryA
b <- tryB a
c <- tryC a b
f c“Do” notation
Examples:
Maybe aIO aData
Control
Data.Functor
Data.Traversable
Control.Applicative
Control.Monad
fmaptraversepure, (<*>)return, (>>=)class Functor t
class Functor t => Traversable t
class Functor m => Applicative m
class Applicative m => Monad mData examples:
[a]Map Int aControl examples:
Maybe aIO a[a]Are lists Data or Control?
instance Applicative [] where
pure x = [x]
fs <*> xs = [f x | f <- fs, x <- xs]instance Applicative ZipList where
pure x = ZipList (repeat x)
(ZipList fs) <*> (ZipList ys) = ZipList (zipWith ($) fs xs)Is Applicative Control, or Data, really?
data Lam a
= Var a
| App (Lam a) (Lam a)
| Abs (Lam (Maybe a))
instance Monad Lam(>>=) :: Lam a -> (a -> Lam b) -> Lam bSubstitution!
Is Monad Control, or Data, really?
data V2 a = V2 a a
data V3 a = V3 a a a
instance Applicative V2
instance Traversable V2
instance Applicative V3
instance Traversable V3sequenceA :: V3 (V2 a) -> V2 (V3 a)V3 (V2 a)Like ZipList
3x2 Matrix
Matrix transpose
forall p f . (Choice p, Applicative f) => p a (f b) -> p s (f t)Photo by Michael Dziedzic on Unsplash
{-# LANGUAGE LinearTypes #-}
f :: a ⊸ b
f x = … -- consumes x exactly onceComing soon to a GHC near you
id x = x✓
linear
dup x = (x,x)✗
not linear
swap (x,y) = (y,x)✓
linear
forget x = ()✗
not linear
f (Left x) = x
f (Right y) = y✓
linear
✓
linear
✗
not linear
h x b = case b of
True -> x
False -> xg z = case z of
Left x -> x
Right y -> yk x b = case b of
True -> x
False -> ()✓
linear
f x = dup x✓
linear
✗
not linear
h u = u 0g x = id (id x)k u = u (u 0)✓
linear
✗
not linear
map f [] = []
map f (x:xs) = f x : map f xsmap :: (a ⊸ b) …map :: (a ⊸ b) -> [a] …map :: (a ⊸ b) -> [a] ⊸ [b]class Functor t where
fmap :: (a ⊸ b) -> t a ⊸ t bf x = dup (\i -> (i, x))✗
not linear
g x = id (\i -> (i, x))✓
linear
Only a linearly consumed closure can have free linear variables
do
x <- f
y <- g x
z <- h x y
k x y z
f >>= \x ->
g x >>= \y ->
h x y >>= \z ->
k x y z(>>=) :: m a ⊸ (a ⊸ m b) ⊸ m b✓
(>>=) :: m a -> (a ⊸ m b) ⊸ m b✗
Free linear variables in non-linear closures
(>>=) :: m a ⊸ (a ⊸ m b) -> m bclass Monad m where
return :: a ⊸ m a
(>>=) :: m a ⊸ (a ⊸ m b) ⊸ m bclass Monad m where
return :: a ⊸ m a
(>>=) :: m a ⊸ (a ⊸ m b) ⊸ m bfmap :: (a ⊸ b) ⊸ m a ⊸ m b
fmap f x = x >>= (\a -> return (f a))class Functor t where
fmap :: (a ⊸ b) -> t a ⊸ t bclass Functor m where
fmap :: (a ⊸ b) ⊸ m a ⊸ m bclass Data.Functor t where
fmap :: (a ⊸ b) -> t a ⊸ t bclass Control.Functor m where
fmap :: (a ⊸ b) ⊸ m a ⊸ m b[a]Maybe aMap Int aV2 aV3 aState s aWriter w aReader e aLam aclass Data.Functor t where
fmap :: (a ⊸ b) -> t a ⊸ t bclass Control.Functor t where
fmap :: (a ⊸ b) ⊸ m a ⊸ m bData structures
Value wrapped in effects
class Data.Applicative t where
pure :: a -> t a
(<*>) :: t (a ⊸ b) ⊸ t a ⊸ t bclass Control.Applicative m where
pure :: a ⊸ m a
(<*>) :: m (a ⊸ b) ⊸ m a ⊸ m bZippable data structures
Static control flow
V2 aV3 aState s aWriter w aReader e aclass Data.Monad t where
return :: a ⊸ t a
(>>=) :: t a ⊸ (a ⊸ t b) -> t bclass Control.Monad m where
return :: a ⊸ m a
(>>=) :: m a ⊸ (a ⊸ m b) ⊸ m bSubstitution
“Do” notation
State s aWriter w aReader e a[a]Maybe aLam a[ k x y z | x <- f, y <- g x, z <- h x y ]comprehension = “do” notation
Is comprehension control?
Photo by Andrej Bauer via Wikimedia commons
(natural transformation)
(+ some laws)
str :: Functor f => a -> f b -> f (a, b)
str a fb = fmap (\b -> (a, b)) fbFree variable
In Hask, all functors/monads are strong
A symmetric monoidal closed category is enriched in itself.
e.g. Hask, LinHask
In such a self-enriched category, strong functors/monads are the same as enriched functors/monads
https://slides.com/aspiwack/haskellove2020
https://github.com/tweag/linear-base/
https://www.tweag.io/blog/2020-01-16-data-vs-control/