0 | module Stellar.API.Morphism
2 | import Stellar.API.Definition
3 | import Stellar.API.Monoid
4 | import public Stellar.Ops
6 | import public Data.Sigma
7 | import Data.Coproduct
10 | import Control.Relation
11 | import Control.Category
12 | import Control.Order
13 | import Control.Comonad
19 | record (=&>) (a, b : API) where
21 | continuation : (x : a.message) -> Σ b.message (\y => b.response y -> a.response x)
24 | (.fwd) : a =&> b -> a.message -> b.message
25 | (.fwd) m x = (m.continuation x).π1
27 | %unbound_implicits on
35 | identity = !! \x => x ## id
39 | (|&>) : a =&> b -> b =&> c -> a =&> c
40 | (|&>) x y = !! \v =>
41 | let v1 ## v2 = x.continuation v
42 | w1 ## w2 = y.continuation v1
49 | Reflexive API (=&>) where
50 | reflexive = identity
53 | Transitive API (=&>) where
57 | Preorder API (=&>) where
63 | Category (=&>) where
72 | bimapEx : a =&> b -> (t -> s) -> Ex a t -> Ex b s
73 | bimapEx m f (MkEx x y) =
74 | let v1 ## v2 = m.continuation x
75 | in MkEx v1 (f . y . v2)
83 | parallel : c1 =&> c2 -> c3 =&> c4 -> (c1 // c3) =&> (c2 // c4)
85 | !! \x => let v1 ## v2 = m1.continuation x.π1
86 | w1 ## w2 = m2.continuation x.π2
87 | in (v1 && w1) ## bimap v2 w2
91 | concurrent : c1 =&> c2 -> c3 =&> c4 -> (c1 * c3) =&> (c2 * c4)
93 | !! \x => let v1 ## v2 = m1.continuation x.π1
94 | w1 ## w2 = m2.continuation x.π2
95 | in (v1 && w1) ## bimap v2 w2
101 | (m1 : a =&> b) -> (m2 : a' =&> b') ->
102 | a &> a' =&> b &> b'
104 | !! \x => let v1 ## v2 = m1.continuation x.req
105 | in MkEx v1 (\xs => π1 (m2.continuation (x.cont (v2 xs))) )
106 | ## \(y1 ## y2) => v2 y1 ## (π2 (m2.continuation (x.cont (v2 y1)))) y2
110 | choice : c1 =&> c2 -> c3 =&> c4 -> (c1 + c3) =&> (c2 + c4)
112 | !! \case (<+ x) => let v1 ## v2 = m1.continuation x
114 | (+> x) => let v1 ## v2 = m2.continuation x
123 | swap : (a // b) =&> (b // a)
124 | swap = !! \x => swap x ## swap
128 | swap' : (x * y) =&> (y * x)
129 | swap' = !! \x => swap x ## Coproduct.swap
134 | dia = !! \case (<+ x) => x ## id
139 | dia3 : a + a + a =&> a
140 | dia3 = choice dia identity |&> dia
144 | inl = !! \x => <+ x ## id
148 | inr = !! \x => +> x ## id
151 | elimChoice : a =&> c -> b =&> c -> a + b =&> c
153 | !! \case (<+ x) => l.continuation x
154 | (+> x) => r.continuation x
158 | pairLUnit : End // a =&> a
159 | pairLUnit = !! \x => x.π2 ## (() &&)
163 | pairRUnit : a // End =&> a
164 | pairRUnit = !! \x => x.π1 ## (&& ())
168 | left : a + Void -> a
173 | right : Void + b -> b
178 | sumLUnit : Never + a =&> a
179 | sumLUnit = !! \(+> x) => x ## id
183 | sumRUnit : a + Never =&> a
184 | sumRUnit = !! \(<+ x) => x ## id
188 | compLUnit : End &> c =&> c
189 | compLUnit = !! \x => x.cont () ## (() ##)
193 | compRUnit : c &> End =&> c
194 | compRUnit = !! \x => x.req ## (## ())
197 | comp2Unit : a =&> End -> b =&> End -> a &> b =&> End
198 | comp2Unit m1 m2 = biSequence m1 m2 |&> compLUnit
206 | State : API -> Type
211 | state : a.message -> State a
212 | state msg = !! \x => msg ## const ()
216 | Costate : API -> Type
217 | Costate = (=&> End)
221 | costate : ((x : a.message) -> a.response x) -> Costate a
222 | costate f = !! \x => () ## const (f x)
226 | extract : Costate a -> (x : a.message) -> a.response x
227 | extract y x = π2 (y.continuation x) ()
231 | runCostate : Costate a -> (x : a.message) -> a.response x
232 | runCostate y x = π2 (y.continuation x) ()
236 | (.getVal) : State a -> a.message
237 | x.getVal = π1 (x.continuation ())
241 | 0 Context : (a, b : API) -> Type
242 | Context a b = Pair (State a) (Costate b)
249 | map_Lift : Functor f => a =&> b -> Lift f a =&> Lift f b
250 | map_Lift c = !! \x => let v1 ## v2 = c.continuation x in v1 ## map v2
254 | counit : Monad m => Lift m a =&> a
255 | counit = !! \x => x ## pure
259 | comult : Monad m => Lift m a =&> Lift m (Lift m a)
260 | comult = !! \x => x ## join
263 | coKleisli : Monad m => Lift m a =&> b -> Lift m b =&> c -> Lift m a =&> c
264 | coKleisli m1 m2 = comult |&> map_Lift m1 |&> m2
268 | pure : Comonad m => a =&> m $- a
269 | pure = !! \x => x ## extract
273 | join : Comonad m => m $- m $- a =&> m $- a
274 | join = !! \x => x ## comult
278 | distrib_plus : Lift f (a + b) =&> Lift f a + Lift f b
280 | !! \case (<+ x) => <+ x ## id
281 | (+> x) => +> x ## id
285 | distrib_plus_3 : Lift f (a + b + c) =&> Lift f a + Lift f b + Lift f c
287 | !! \case (<+ (<+ x)) => <+ <+ x ## id
288 | (<+ (+> x)) => <+ +> x ## id
289 | (+> x) => +> x ## id
292 | lift_IO : HasIO io => io $- a =&> IO $- a
293 | lift_IO = !! \x => x ## liftIO
301 | run : (x : State a) -> Costate a -> a.response x.getVal
302 | run x y = extract y x.getVal
306 | seq2M : Monad m => Costate (Lift m a) -> Costate (Lift m b) -> Costate (Lift m (a &> b))
307 | seq2M x y = costate
308 | (\xn => do v1 <- extract x xn.req
309 | v2 <- extract y (xn.cont v1)
314 | runSequenceM3 : Monad m =>
315 | (input : State (a &> b &> c)) ->
316 | Costate (Lift m a) -> Costate (Lift m b) -> Costate (Lift m c) ->
317 | m ((a &> b &> c).response input.getVal)
318 | runSequenceM3 inp x y z =
319 | let xn : Costate (Lift m (a &> b))
321 | yn : Costate (Lift m ((a &> b) &> c))
322 | yn = seq2M {m, a = a &> b, b = c} xn z
323 | in run {a = Lift m (a &> b &> c)} (state inp.getVal) yn
326 | forward : (a -> b) -> (a :- c) =&> (b :- c)
327 | forward f = !! \x => f x ## id
330 | backward : (a -> b) -> (c :- b) =&> (c :- a)
331 | backward f = !! \x => x ## f
338 | trace : Show a => (forall x. Show (b x)) => (!>) a b =&> (!>) a b
339 | trace = !! \x => x ## (\y => trace "fwd input: \{show x}\nbwd input: \{show y}" y)
342 | traceFwd : Show a => (!>) a b =&> (!>) a b
343 | traceFwd = !! \x => x ## (\y => trace "fwd input: \{show x}" y)
346 | traceBwd : (forall x. Show (b x)) => (!>) a b =&> (!>) a b
347 | traceBwd = !! \x => x ## (\y => trace "bwd input: \{show y}" y)