1 {-# LANGUAGE RankNTypes, FlexibleInstances, UndecidableInstances, TypeFamilies, MultiParamTypeClasses #-}
2 -----------------------------------------------------------------------------
4 -- | The instance witnessing contextual closure of GArrowSTKC.
6 -- Module : GHC.HetMet.GArrowKappa
8 -- License : public domain
10 -- Maintainer : Adam Megacz <megacz@acm.org>
11 -- Stability : experimental
12 -- Portability : portable
14 module GHC.HetMet.GArrowKappa (
15 -- | It's easy to write a function with this type:
17 -- > homfunctor :: (GArrow g (,) () => g a b -> (g () a -> g () b))
19 -- ... it's nothing more than the precomposition function:
23 -- however, writing its *inverse* is not so easy:
25 -- > homfunctor_inv :: (GArrow g (,) () => (g () a -> g () b) -> g a b)
27 -- Think about it. This is saying that every way of turning a @(g ()
28 -- a)@ into a @(g () b)@ is equivalent to precomposition, for some
29 -- magically-divined value of type @(g a b)@. That's hard to believe!
30 -- In fact, it's flat out false unless we exploit parametricity. This
31 -- module does that, and wraps up all of the magic in an easy-to-use
32 -- implementation of homfunctor_inv.
34 -- Note that @homfunctor_inv@ needs instances of @GArrowDrop@,
35 -- @GArrowCopy@, and @GArrowSwap@ in order to work this magic.
40 -- * Category Theoretic Background
43 -- * Contextual Completeness
46 import Control.Category ( (>>>) )
47 import qualified Control.Category
48 import GHC.HetMet.GArrow
50 newtype Polynomial g t x y = Polynomial { unPoly :: g (GArrowTensor g x t) y }
52 instance GArrowSTKC g => Control.Category.Category (Polynomial g t) where
53 id = Polynomial { unPoly = ga_second ga_drop >>> ga_cancelr }
54 (.) g f = Polynomial { unPoly = ga_second ga_copy >>> ga_unassoc >>> ga_first (unPoly f) >>> (unPoly g) }
56 instance (GArrowSTKC g, (GArrowTensor g) ~ (**), (GArrowUnit g) ~ u) => GArrow (Polynomial g t) (**) u where
57 ga_first f = Polynomial { unPoly = ga_assoc >>> ga_second ga_swap >>> ga_unassoc >>> ga_first (unPoly f) }
58 ga_second f = Polynomial { unPoly = ga_assoc >>> ga_second (unPoly f) }
59 ga_cancell = Polynomial { unPoly = ga_second ga_drop >>> ga_cancelr >>> ga_cancell }
60 ga_cancelr = Polynomial { unPoly = ga_second ga_drop >>> ga_cancelr >>> ga_cancelr }
61 ga_uncancell = Polynomial { unPoly = ga_second ga_drop >>> ga_cancelr >>> ga_uncancell }
62 ga_uncancelr = Polynomial { unPoly = ga_second ga_drop >>> ga_cancelr >>> ga_uncancelr }
63 ga_assoc = Polynomial { unPoly = ga_second ga_drop >>> ga_cancelr >>> ga_assoc }
64 ga_unassoc = Polynomial { unPoly = ga_second ga_drop >>> ga_cancelr >>> ga_unassoc }
66 type instance GArrowUnit (Polynomial g t) = GArrowUnit g
68 type instance GArrowTensor (Polynomial g t) = GArrowTensor g
70 instance (GArrowSTKC g, (GArrowTensor g) ~ (**), (GArrowUnit g) ~ u) => GArrowDrop (Polynomial g t) (**) u
72 ga_drop = Polynomial { unPoly = ga_second ga_drop >>> ga_cancelr >>> ga_drop }
74 instance (GArrowSTKC g, (GArrowTensor g) ~ (**), (GArrowUnit g) ~ u) => GArrowCopy (Polynomial g t) (**) u
76 ga_copy = Polynomial { unPoly = ga_second ga_drop >>> ga_cancelr >>> ga_copy }
78 instance (GArrowSTKC g, (GArrowTensor g) ~ (**), (GArrowUnit g) ~ u) => GArrowSwap (Polynomial g t) (**) u
80 ga_swap = Polynomial { unPoly = ga_second ga_drop >>> ga_cancelr >>> ga_swap }
82 instance GArrowSTKC g => GArrowSTKC (Polynomial g t)
85 -- | Given an **instance-polymorphic** Haskell function @(g () a)->(g () b)@ we can produce
86 -- a self-contained instance-polymorphic term @(g a b)@. The "trick" is that we supply
87 -- the instance-polymorphic Haskell function with a modified dictionary (type class instance)
89 homfunctor_inv :: (forall g . GArrowSTKC g => g (GArrowUnit g) a -> g (GArrowUnit g) b) ->
90 (forall g . GArrowSTKC g => g a b)
91 homfunctor_inv x = ga_uncancell >>> unPoly (x (Polynomial { unPoly = ga_cancell }))
96 -- A few more comments are in order. First of all, the function
97 -- @homfunctor@ above really is a hom-functor; its domain is the
98 -- category whose objects are Haskell types and whose morphisms a->b
99 -- are Haskell terms of type @(GArrow g => g a b)@ -- note how the
100 -- term is polymorphic in @g@. This category is Hask-enriched: for
101 -- each choice of @a@ and @b@, the collection of all morphisms a->b
102 -- happens to be a Hask-object, and all the other necessary conditions
108 -- Material below is in flux; take with a grain of salt...
110 -- A category C with a terminal object 1 is *contextually complete* if
111 -- choosing an object x of C and freely adjoining and "opaque"
112 -- morphism 1->x to form a __polynomial category__ C[x] it is the case
113 -- that C[x] can be "represented in" C. The technical definition of
114 -- "represented in" is that the inclusion functor C->C[x] have a left
115 -- adjoint. This left adjoint kappa_x:C[x]->C has the property that
117 -- > C(kappa_x(a),b) \cong C[x](a,b)
119 -- See Hasegawa, __Decomposing typed lambda calculus into a
120 -- couple of categorical programming languages__.
122 -- Most notions in category theory come in both ordinary and enriched
123 -- versions. I'm not aware of an enriched version of contextual
124 -- closure, it ought to be something along the lines of saying
125 -- that, for C a V-enriched category, V(C(1,a),C(x,y)) is isomorphic
126 -- (as a V-object) to V(1,C(a**x,y)). When x=1 this is exactly the
127 -- same thing as saying that hom(1,-):C->V is a full and faithful functor.
129 -- Usually C is monoidal and a morphism a->b in C[x] is "represented
130 -- by" a morphism (a**x)->b in C where (**) is the monoidal tensor.
131 -- Contextual closure is a way of saying that the tensor of C can
132 -- represent contexts -- that a morphism into (a**x) is just as good
133 -- as a morphism into a in C[x].
136 -- Since every contextually complete
138 -- Most notions in category theory come in both ordinary and enriched
139 -- versions. I'm not aware of an enriched version of contextual
140 -- closure, but consider this: if both C and C[x] are Sets-enriched,
141 -- (i.e., ordinary categories) we know that
143 -- > C[x](a,b) \sqsubset Sets( C(1,x) , C(a,b) )
145 -- where \sqsubset means "embeds in" -- in this case, as a
146 -- Sets-object. Think about it; the construction of C[x] dictates
147 -- that its morphisms a->b are nothing more than strategies for
148 -- building a C-morphism a->b using a free 1->x morphism as a
149 -- parameter. You're only allowed to use composition and other
150 -- categorical tools for putting together this strategy, so the
151 -- relationship above is just an embedding -- there might be
152 -- paradoxical mappings from C(1,x) to C(a,b) that don't arise as the
153 -- result of sensible constructions.
155 -- I claim that the embedding above, with V substituted for Sets,
156 -- should hold for any sensible definition of enriched contextual
159 -- > V( 1 , C[x](a,b) ) \sqsubset V( C(1,x) , C(a,b) )
161 -- substituting the isomorphism above, we get:
163 -- > V( 1 , C(kappa_x(a),b) ) \sqsubset V( C(1,x) , C(a,b) )
165 -- Now, let a=1 and we have:
167 -- > V( 1 , C(kappa_x(1),b) ) \sqsubset V( C(1,x) , C(1,b) )
169 -- If kappa_x(1) \cong x then
171 -- > V( 1 , C(x,b) ) \sqsubset V( C(1,x) , C(1,b) )