Safe Haskell | Safe |
---|---|
Language | Haskell2010 |
Overloaded Categories, desugar Arrow
into classes in this module.
Enabled with
{-# OPTIONS -fplugin=Overloaded -fplugin-opt=Overloaded:Categories #-}
Description
Arrows
notation - GHC manual chapter -
is cool, but it desugars into "wrong" classes.
The arr
combinator is used for plumbing. We should desugar to proper
type-classes:
CartesianCategory
, notArrow
CocartesianCategory
, notArrowChoice
(implementation relies onBicartesianCategory
)CCC
, notArrowApply
(not implemented yet)
Examples
Expression like
catAssoc ::CartesianCategory
cat => cat (Product
cat (Product
cat a b) c) (Product
cat a (Product
cat b c)) catAssoc = proc ((x, y), z) ->identity
-< (x, (y, z))
are desugared to (a mess which is)
fanout
(proj1
%%
proj1
) (fanout
(proj2
%%
proj1
)proj2
)
If you are familiar with arrows-operators, this is similar to
(fst
.fst
)&&&
(snd
.fst
&&&
snd
)
expression.
The catAssoc
could be instantiated to cat = (->)
,
or more interestingly for example instantiate it to STLC morphisms to get an expression
like:
Lam (Pair (Fst (Fst (Var Here))) (Pair (Snd (Fst (Var Here))) (Snd (Var Here))))
proc
notation is nicer than writing de Bruijn indices.
This is very similar idea to Conal Elliott's Compiling to Categories work. This approach is syntactically more heavy, but works in more correct stage of compiler, before actual desugarer.
As one more example, we implement the automatic differentiation, as in Conal's paper(s). To keep things simple we use
newtype AD a b = AD (a -> (b, a -> b))
representation, i.e. use ordinary maps to represent linear maps. We then define a function
evaluateAD :: Functor f => AD a b -> a -> f a -> (b, f b) evaluateAD (AD f) x xs = let (y, f') = f x in (y, fmap f' xs)
which would allow to calculuate function value and derivatives in given directions. Then we can define simple quadratic function:
quad :: AD (Double, Double) Double quad = proc (x, y) -> do x2 <- mult -< (x, x) y2 <- mult -< (y, y) plus -< (x2, y2)
It's not as simple as writing quad x y = x * x + y * y
,
but not too far.
Then we can play with it. At origo everything is zero:
let sqrthf = 1 / sqrt 2 in evaluateAD quad (0, 0) [(1,0), (0,1), (sqrthf, sqrthf)] = (0.0,[0.0,0.0,0.0])
If we evaluate at some other point, we see things working:
evaluateAD quad (1, 2) [(1,0), (0,1), (sqrthf, sqrthf)] = (5.0,[2.0,4.0,4.242640687119285])
Obviously, if we would use inspectable representation for linear maps,
as Conal describe, we'd get more benefits. And then arr
wouldn't
be definable!
Synopsis
- class Category (cat :: k -> k -> Type)
- identity :: Category cat => cat a a
- (%%) :: Category cat => cat b c -> cat a b -> cat a c
- class Category cat => CategoryWith1 (cat :: k -> k -> Type) where
- class CategoryWith1 cat => CartesianCategory (cat :: k -> k -> Type) where
- class Category cat => CocartesianCategory (cat :: k -> k -> Type) where
- class (CartesianCategory cat, CocartesianCategory cat) => BicartesianCategory cat where
- class CartesianCategory cat => CCC (cat :: k -> k -> Type) where
- type Exponential cat :: k -> k -> k
- eval :: cat (Product cat (Exponential cat a b) a) b
- transpose :: cat (Product cat a b) c -> cat a (Exponential cat b c)
- class Category cat => GeneralizedElement (cat :: k -> k -> Type) where
Documentation
class Category (cat :: k -> k -> Type) #
A class for categories. Instances should satisfy the laws
f.
id
= f -- (right identity)id
.
f = f -- (left identity) f.
(g.
h) = (f.
g).
h -- (associativity)
Instances
Category (Coercion :: k -> k -> Type) | Since: base-4.7.0.0 |
Category ((:~:) :: k -> k -> Type) | Since: base-4.7.0.0 |
Category ((:~~:) :: k -> k -> Type) | Since: base-4.10.0.0 |
(Category p, Category q) => Category (Product p q :: k -> k -> Type) | |
(Applicative f, Category p) => Category (Tannen f p :: k -> k -> Type) | |
(Applicative f, Monad f) => Category (WhenMissing f :: Type -> Type -> Type) | Since: containers-0.5.9 |
Defined in Data.IntMap.Internal id :: WhenMissing f a a # (.) :: WhenMissing f b c -> WhenMissing f a b -> WhenMissing f a c # | |
Category ((->) :: Type -> Type -> Type) | Since: base-3.0 |
Defined in Control.Category | |
(Monad f, Applicative f) => Category (WhenMatched f x :: Type -> Type -> Type) | Since: containers-0.5.9 |
Defined in Data.IntMap.Internal id :: WhenMatched f x a a # (.) :: WhenMatched f x b c -> WhenMatched f x a b -> WhenMatched f x a c # | |
(Applicative f, Monad f) => Category (WhenMissing f k :: Type -> Type -> Type) | Since: containers-0.5.9 |
Defined in Data.Map.Internal id :: WhenMissing f k a a # (.) :: WhenMissing f k b c -> WhenMissing f k a b -> WhenMissing f k a c # | |
(Monad f, Applicative f) => Category (WhenMatched f k x :: Type -> Type -> Type) | Since: containers-0.5.9 |
Defined in Data.Map.Internal id :: WhenMatched f k x a a # (.) :: WhenMatched f k x b c -> WhenMatched f k x a b -> WhenMatched f k x a c # |
class Category cat => CategoryWith1 (cat :: k -> k -> Type) where Source #
Category with terminal object.
class CategoryWith1 cat => CartesianCategory (cat :: k -> k -> Type) where Source #
Cartesian category is a monoidal category where monoidal product is the categorical product.
class Category cat => CocartesianCategory (cat :: k -> k -> Type) where Source #
Cocartesian category is a monoidal category where monoidal product is the categorical coproduct.
class (CartesianCategory cat, CocartesianCategory cat) => BicartesianCategory cat where Source #
Bicartesian category is category which is both cartesian and cocartesian.
We also require distributive morpism.
class CartesianCategory cat => CCC (cat :: k -> k -> Type) where Source #
Closed cartesian category.
type Exponential cat :: k -> k -> k Source #
represents \(B^A\). This is due how (->) works.Exponential
cat a b
eval :: cat (Product cat (Exponential cat a b) a) b Source #
transpose :: cat (Product cat a b) c -> cat a (Exponential cat b c) Source #
Instances
CCC ((->) :: Type -> Type -> Type) Source # | |
Defined in Overloaded.Categories type Exponential (->) :: k -> k -> k Source # eval :: Product (->) (Exponential (->) a b) a -> b Source # transpose :: (Product (->) a b -> c) -> a -> Exponential (->) b c Source # |
class Category cat => GeneralizedElement (cat :: k -> k -> Type) where Source #