Data vs Control

A tale of two functors

Arnaud Spiwack

Data and Control

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 b
traverse
  :: Applicative f => (a -> f b) -> t a -> f (t b)

Data

Examples:

[a]
Map Int a

Data and Control

Data

Control

Data.Functor

Data.Traversable

Control.Applicative

Control.Monad

fmap
traverse

Control

Control.Applicative

Control.Monad

pure :: a -> m a
(<*>) :: m (a -> b) -> m a -> m b
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
do
  a <- tryA
  b <- tryB a
  c <- tryC a b
  f c

“Do” notation

Examples:

Maybe a
IO a

Data and Control

Data

Control

Data.Functor

Data.Traversable

Control.Applicative

Control.Monad

fmap
traverse
pure, (<*>)
return, (>>=)

Yeaaah, but…

class Functor t

class Functor t => Traversable t

class Functor m => Applicative m

class Applicative m => Monad m

And, thinking about it…

Data examples:

[a]
Map Int a

Control examples:

Maybe a
IO a
[a]

Are lists Data or Control?

One last thing

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?

Ok, one last thing

data Lam a
  = Var a
  | App (Lam a) (Lam a)
  | Abs (Lam (Maybe a))
  
instance Monad Lam
(>>=) :: Lam a -> (a -> Lam b) -> Lam b

Substitution!

Is Monad Control, or Data, really?

Ok ok, one last thing

data V2 a = V2 a a

data V3 a = V3 a a a

instance Applicative V2
instance Traversable V2
instance Applicative V3
instance Traversable V3
sequenceA :: V3 (V2 a) -> V2 (V3 a)
V3 (V2 a)

Like ZipList

3x2 Matrix

Matrix transpose

A prism

forall p f . (Choice p, Applicative f) => p a (f b) -> p s (f t)

A prism

Linear types

{-# LANGUAGE LinearTypes #-}

f :: a ⊸ b
f x = … -- consumes x exactly once

Coming soon to a GHC near you

Linear types, by examples (1/3)

id x = x

linear

dup x = (x,x)

not linear

swap (x,y) = (y,x)

linear

forget x = ()

not linear

Linear types, by examples (2/3)

f (Left x) = x
f (Right y) = y

linear

linear

not linear

h x b = case b of
  True -> x
  False -> x
g z = case z of
  Left x -> x
  Right y -> y
k x b = case b of
  True -> x
  False -> ()

linear

Linear types, by examples (3/3)

f x = dup x

linear

not linear

h u = u 0
g x = id (id x)
k u = u (u 0)

linear

not linear

What about map?

map f [] = []
map f (x:xs) = f x : map f xs
map :: (a ⊸ b) …
map :: (a ⊸ b) -> [a] …
map :: (a ⊸ b) -> [a] ⊸ [b]

Linear functors

class Functor t where
  fmap :: (a ⊸ b) -> t a ⊸ t b

Linear types and closures

f 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” notation

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 b

Linear monads

class Monad m where
  return :: a ⊸ m a
  (>>=) :: m a ⊸ (a ⊸ m b) ⊸ m b

Linear monads

class Monad m where
  return :: a ⊸ m a
  (>>=) :: m a ⊸ (a ⊸ m b) ⊸ m b
fmap :: (a ⊸ b) ⊸ m a ⊸ m b
fmap f x = x >>= (\a -> return (f a))

Linear functors?

class Functor t where
  fmap :: (a ⊸ b) -> t a ⊸ t b
class Functor m where
  fmap :: (a ⊸ b) ⊸ m a ⊸ m b
class Data.Functor t where
  fmap :: (a ⊸ b) -> t a ⊸ t b
class Control.Functor m where
  fmap :: (a ⊸ b) ⊸ m a ⊸ m b

Linear functors!

Data vs Control: Functor

[a]
Maybe a
Map Int a
V2 a
V3 a
State s a
Writer w a
Reader e a
Lam a
class Data.Functor t where
  fmap :: (a ⊸ b) -> t a ⊸ t b
class Control.Functor t where
  fmap :: (a ⊸ b) ⊸ m a ⊸ m b

Data structures

Value wrapped in effects

Data vs Control: Applicatives

class Data.Applicative t where
  pure :: a -> t a
  (<*>) :: t (a ⊸ b) ⊸ t a ⊸ t b
class Control.Applicative m where
  pure :: a ⊸ m a
  (<*>) :: m (a ⊸ b) ⊸ m a ⊸ m b

Zippable data structures

Static control flow

V2 a
V3 a
State s a
Writer w a
Reader e a

Data vs Control: Monads

class Data.Monad t where
  return :: a ⊸ t a
  (>>=) :: t a ⊸ (a ⊸ t b) -> t b
class Control.Monad m where
  return :: a ⊸ m a
  (>>=) :: m a ⊸ (a ⊸ m b) ⊸ m b

Substitution

“Do” notation

State s a
Writer w a
Reader e a
[a]
Maybe a
Lam a

Side note: comprehension

[ k x y z | x <- f, y <- g x, z <- h x y ]

comprehension = “do” notation

Is comprehension control?

Eugenio Moggi

Strong functors

(natural transformation)

A\otimes F(B) \longrightarrow F(A\otimes B)

(+ some laws)

str :: Functor f => a -> f b -> f (a, b)
str a fb = fmap (\b -> (a, b)) fb

Free variable

Conflation theorem

Theorem:

In Hask, all functors/monads are strong

Enriched categories

Theorem 1:

A symmetric monoidal closed category is enriched in itself.

Symmetric monoidal closed categories:

e.g. Hask, LinHask

Theorem 2:

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/

Data vs Control: a tale of two functors

By Arnaud Spiwack

Data vs Control: a tale of two functors

The Haskell base library features the Data and Control module hierarchies. The distinction between data and control is rooted deeply, in computer science: it can already be seen in Turing machines. However, when it comes to Haskell the difference between data and control can be quite muddled. A case in point is functors: there are functor type classes in both hierarchies: Functor and Traversable are in the Data hierarchy, while Applicative and Monad are in the Control hierarchy. This is really confusing! Do functors magically cease to be data and become control structure when I declare a Applicative instance? In this talk, I will show that there are indeed two kinds of functors, which I dub data functors, and control functors. Each fitting in the respective hierarchy. The catch is that you can't tell them apart in regular Haskell. However, with the new linear types extension, we can see them for what they really are. In fact, when programming with linear types, one typically needs both kinds. I'll be explaining a tiny bit of linear types, just enough to expose the two hierarchies for what they are.

  • 727