squares-0.2: The double category of Hask functors and profunctors
LicenseBSD-style (see the file LICENSE)
Maintainersjoerd@w3future.com
Safe HaskellSafe-Inferred
LanguageHaskell2010

Data.Square

Description

 
Synopsis

Double category

There is a double category of Haskell functors and profunctors.

The squares in this double category are natural transformations.

emptySquare :: Square '[] '[] '[] '[] Source #

+-----+
|     |
|     |
|     |
+-----+
forall a b. (a -> b) -> (a -> b)

The empty square is the identity transformation.

proId :: Profunctor p => Square '[p] '[p] '[] '[] Source #

+-----+
|     |
p-----p
|     |
+-----+
forall a b. p a b -> p a b

Profunctors are drawn as horizontal lines.

Note that emptySquare is proId for the profunctor (->). We don't draw a line for (->) because it is the identity for profunctor composition.

funId :: Functor f => Square '[] '[] '[f] '[f] Source #

+--f--+
|  |  |
|  v  |
|  |  |
+--f--+
forall a b. (a -> b) -> (f a -> f b)

Functors are drawn with vertical lines with arrow heads. You will recognize the above type as fmap!

We don't draw lines for the identity functor, because it is the identity for functor composition.

funNat :: (Functor f, Functor g) => (f ~> g) -> Square '[] '[] '[f] '[g] Source #

+--f--+
|  |  |
|  @  |
|  |  |
+--g--+
forall a b. (a -> b) -> (f a -> g b)

Non-identity transformations are drawn with an @ in the middle. Natural transformations between haskell functors are usualy given the type forall a. f a -> g a. The type above you get when fmapping before or after. (It doesn't matter which, because of naturality!)

proNat :: (Profunctor p, Profunctor q) => (p :-> q) -> Square '[p] '[q] '[] '[] Source #

+-----+
|     |
p--@--q
|     |
+-----+
forall a b. p a b -> q a b

Natural transformations between profunctors.

newtype SquareNT p q f g Source #

+--f--+
|  v  |
p--@--q
|  v  |
+--g--+
forall a b. p a b -> q (f a) (g b)

The complete definition of a square is a combination of natural transformations between functors and natural transformations between profunctors.

To make type inferencing easier the above type is wrapped by a newtype.

Constructors

Square 

Fields

  • unSquare :: forall a b. p a b -> q (f a) (g b)
     

type Square ps qs fs gs = SquareNT (PList ps) (PList qs) (FList fs) (FList gs) Source #

To make composing squares associative, this library uses squares with lists of functors and profunctors, which are composed together.

FList '[] a ~ a
FList '[f, g, h] a ~ h (g (f a))
PList '[] a b ~ a -> b
PList '[p, q, r] a b ~ (p a x, q x y, r y b)

mkSquare :: (IsPList ps, IsPList qs, IsFList fs, IsFList gs, Profunctor (PList qs)) => (forall a b. PlainP ps a b -> PlainP qs (PlainF fs a) (PlainF gs b)) -> Square ps qs fs gs Source #

A helper function to add the wrappers needed for PList and FList.

runSquare :: (IsPList ps, IsPList qs, IsFList fs, IsFList gs, Profunctor (PList qs)) => Square ps qs fs gs -> PlainP ps a b -> PlainP qs (PlainF fs a) (PlainF gs b) Source #

A helper function to remove the wrappers needed for PList and FList.

(|||) :: (Profunctor (PList rs), IsFList fs, IsFList gs, Functor (FList hs), Functor (FList is)) => Square ps qs fs gs -> Square qs rs hs is -> Square ps rs (fs ++ hs) (gs ++ is) infixl 6 Source #

+--f--+     +--h--+       +--f--h--+
|  v  |     |  v  |       |  v  v  |
p--@--q ||| q--@--r  ==>  p--@--@--r
|  v  |     |  v  |       |  v  v  |
+--g--+     +--i--+       +--g--i--+

Horizontal composition of squares. proId is the identity of (|||). This is regular function composition of the underlying functions.

(===) :: (IsPList ps, IsPList qs, Profunctor (PList qs), Profunctor (PList ss)) => Square ps qs fs gs -> Square rs ss gs hs -> Square (ps ++ rs) (qs ++ ss) fs hs infixl 5 Source #

+--f--+
|  v  |
p--@--q              +--f--+
|  v  |              |  v  |
+--g--+              p--@--q
  ===        ==>     |  v  |
+--g--+              r--@--s
|  v  |              |  v  |
r--@--s              +--h--+
|  v  |
+--h--+

Vertical composition of squares. funId is the identity of (===).

Proarrow equipment

The double category of haskell functors and profunctors is a proarrow equipment. Which means that we can "bend" functors to become profunctors.

toRight :: Functor f => Square '[] '[Star f] '[f] '[] Source #

+--f--+
|  v  |
|  \->f
|     |
+-----+

A functor f can be bent to the right to become the profunctor Star f.

toLeft :: Square '[Costar f] '[] '[f] '[] Source #

+--f--+
|  v  |
f<-/  |
|     |
+-----+

A functor f can be bent to the left to become the profunctor Costar f.

fromRight :: Functor f => Square '[] '[Costar f] '[] '[f] Source #

+-----+
|     |
|  /-<f
|  v  |
+--f--+

The profunctor Costar f can be bent down to become the functor f again.

fromLeft :: Square '[Star f] '[] '[] '[f] Source #

+-----+
|     |
f>-\  |
|  v  |
+--f--+

The profunctor Star f can be bent down to become the functor f again.

uLeft :: Functor f => Square '[Star f, Costar f] '[] '[] '[] Source #

+-----+
f>-\  |         fromLeft
|  v  |         ===
f<-/  |         toLeft
+-----+

fromLeft and toLeft can be composed vertically to bend Star f back to Costar f.

uRight :: Functor f => Square '[] '[Costar f, Star f] '[] '[] Source #

+-----+
|  /-<f         fromRight
|  v  |         ===
|  \->f         toRight
+-----+

fromRight and toRight can be composed vertically to bend Costar f to Star f.

toRight2 :: (Functor f, Functor g) => Square '[] '[Star g, Star f] '[f, g] '[] Source #

+-f-g-+
| v \>g         funId ||| toRight
| |   |         ===
| \-->f         toRight
+-----+

toLeft2 :: (Functor f, Functor g) => Square '[Costar f, Costar g] '[] '[f, g] '[] Source #

+-f-g-+
f</ v |         toLeft ||| funId
|   | |         ===
g<--/ |         toLeft
+-----+

fromRight2 :: (Functor f, Functor g) => Square '[] '[Costar f, Costar g] '[] '[f, g] Source #

+-----+
| /--<f         fromRight
| |   |         ===
| v /<g         funId ||| fromRight
+-f-g-+

fromLeft2 :: (Functor f, Functor g) => Square '[Star g, Star f] '[] '[] '[f, g] Source #

+-----+
g>--\ |         fromLeft
|   | |         ===
f>\ | |         fromLeft ||| funId
+-f-g-+

spiderLemma :: (Profunctor p, Profunctor q, Functor f1, Functor f2, Functor f3, Functor g1, Functor g2, Functor g3) => Square '[p] '[q] '[f1, f2, f3] '[g1, g2, g3] -> Square '[Star f1, p, Costar g1] '[Costar f3, q, Star g3] '[f2] '[g2] Source #

+f-f-f+     +--f--+     spiderLemma n =
|v v v|     f> v <f       fromLeft ||| funId ||| fromRight
| \|/ |     | \|/ |       ===
p--@--q ==> p--@--q       n
| /|\ |     | /|\ |       ===
|v v v|     g< v >g       toLeft ||| funId ||| toRight
+g-g-g+     +--g--+

The spider lemma is an example how bending wires can also be seen as sliding functors around corners.

spiderLemma' :: (Profunctor p, Profunctor q, Functor f1, Functor f2, Functor f3, Functor g1, Functor g2, Functor g3) => Square '[Star f1, p, Costar g1] '[Costar f3, q, Star g3] '[f2] '[g2] -> Square '[p] '[q] '[f1, f2, f3] '[g1, g2, g3] Source #

spiderLemma' n = (toRight === proId === fromRight) ||| n ||| (toLeft === proId === fromLeft)

The spider lemma in the other direction.

In other categories than Hask

A--f--C
|  v  |
p--@--q
|  v  |
B--g--D

Squares can be generalized further by choosing a different category for each quadrant. To use this, SquareNT has been made kind polymorphic:

type SquareNT :: (a -> b -> Type) -> (c -> d -> Type) -> (a -> c) -> (b -> d) -> Type

This library is mostly about staying in Hask, but it is interesting to use f.e. the product category Hask × Hask or the unit category.

type Square21 ps1 ps2 qs f g = SquareNT (PList ps1 :**: PList ps2) (PList qs) (UncurryF f) (UncurryF g) Source #

H²-f--H
|  v  |
p--@--q     H = Hask, H² = Hask x Hask
|  v  |
H²-g--H

data (p1 :**: p2) a b where Source #

Combine two profunctors from Hask to a profunctor from Hask x Hask

Constructors

(:**:) :: p1 a1 b1 -> p2 a2 b2 -> (p1 :**: p2) '(a1, a2) '(b1, b2) 

data UncurryF f a where Source #

Uncurry the kind of a bifunctor.

type UncurryF :: (a -> b -> Type) -> (a, b) -> Type

Constructors

UncurryF 

Fields

type Square01 qs a b = SquareNT Unit (PList qs) (ValueF a) (ValueF b) Source #

1--a--H
|  v  |
U--@--q     1 = Hask^0 = (), H = Hask
|  v  |
1--b--H

data Unit a b where Source #

The boring profunctor from and to the unit category.

Constructors

Unit :: Unit '() '() 

data ValueF x u where Source #

Values as a functor from the unit category.

Constructors

ValueF :: a -> ValueF a '()