License | BSD-style (see the file LICENSE) |
---|---|
Maintainer | sjoerd@w3future.com |
Safe Haskell | Safe-Inferred |
Language | Haskell2010 |
Synopsis
- emptySquare :: Square '[] '[] '[] '[]
- proId :: Profunctor p => Square '[p] '[p] '[] '[]
- funId :: Functor f => Square '[] '[] '[f] '[f]
- funNat :: (Functor f, Functor g) => (f ~> g) -> Square '[] '[] '[f] '[g]
- proNat :: (Profunctor p, Profunctor q) => (p :-> q) -> Square '[p] '[q] '[] '[]
- newtype SquareNT p q f g = Square {
- 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)
- 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
- 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)
- (|||) :: (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)
- (===) :: (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
- toRight :: Functor f => Square '[] '[Star f] '[f] '[]
- toLeft :: Square '[Costar f] '[] '[f] '[]
- fromRight :: Functor f => Square '[] '[Costar f] '[] '[f]
- fromLeft :: Square '[Star f] '[] '[] '[f]
- uLeft :: Functor f => Square '[Star f, Costar f] '[] '[] '[]
- uRight :: Functor f => Square '[] '[Costar f, Star f] '[] '[]
- toRight2 :: (Functor f, Functor g) => Square '[] '[Star g, Star f] '[f, g] '[]
- toLeft2 :: (Functor f, Functor g) => Square '[Costar f, Costar g] '[] '[f, g] '[]
- fromRight2 :: (Functor f, Functor g) => Square '[] '[Costar f, Costar g] '[] '[f, g]
- fromLeft2 :: (Functor f, Functor g) => Square '[Star g, Star f] '[] '[] '[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]
- 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]
- type Square21 ps1 ps2 qs f g = SquareNT (PList ps1 :**: PList ps2) (PList qs) (UncurryF f) (UncurryF g)
- data (p1 :**: p2) a b where
- data UncurryF f a where
- type Square01 qs a b = SquareNT Unit (PList qs) (ValueF a) (ValueF b)
- data Unit a b where
- data ValueF x u where
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 fmap
ping 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.
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 #
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 #
(|||) :: (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 #
(===) :: (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 #
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
can be bent down to become the functor Costar
ff
again.
fromLeft :: Square '[Star f] '[] '[] '[f] Source #
+-----+ | | f>-\ | | v | +--f--+
The profunctor
can be bent down to become the functor Star
ff
again.
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
data UncurryF f a where Source #
Uncurry the kind of a bifunctor.
type UncurryF :: (a -> b -> Type) -> (a, b) -> Type
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
The boring profunctor from and to the unit category.