@@ -1,8 +1,19 @@
1-- | Combinator for process closures
1-- | Combinator for process closures
2{-# LANGUAGE MagicHash #-}
2{-# LANGUAGE MagicHash #-}
3module Control.Distributed.Process.Internal.Closure.CP
3module Control.Distributed.Process.Internal.Closure.CP
4+ ( -- * Definition of CP and the generalized arrow combinators
4− ( -- * Closure versions of CH primitives
15+ -- * Closure versions of CH primitives
6 , cpUnlink
17 , cpUnlink
8 , cpExpect
19 , cpExpect
@@ -18,8 +29,9 @@ module Control.Distributed.Process.Internal.Closure.CP
18import Data.Binary (encode)
29import Data.Binary (encode)
19import Data.ByteString.Lazy (ByteString)
30import Data.ByteString.Lazy (ByteString)
20import Data.Typeable (Typeable, typeOf, typeRepTyCon, TyCon)
31import Data.Typeable (Typeable, typeOf, typeRepTyCon, TyCon)
32+import Data.Typeable.Internal (TypeRep(..))
21import Control.Applicative ((<$>))
33import Control.Applicative ((<$>))
22−import Control.Monad (join)
34+import Control.Monad ((>=>))
23import Control.Distributed.Process.Serializable (Serializable)
35import Control.Distributed.Process.Serializable (Serializable)
24import Control.Distributed.Process.Internal.Types
36import Control.Distributed.Process.Internal.Types
25 ( Closure(Closure)
37 ( Closure(Closure)
@@ -53,14 +65,17 @@ import Control.Distributed.Process.Internal.Closure.Static
53 , staticSplit
65 , staticSplit
54 , staticConst
66 , staticConst
55 , staticUnit
67 , staticUnit
56 , sdictProcessId
71 , sdictProcessId
58import Control.Distributed.Process.Internal.Closure.MkClosure (mkClosure)
73import Control.Distributed.Process.Internal.Closure.MkClosure (mkClosure)
59import Control.Distributed.Process.Internal.Dynamic
74import Control.Distributed.Process.Internal.Dynamic
60 ( Dynamic(Dynamic)
75 ( Dynamic(Dynamic)
62 , unsafeCoerce#
76 , unsafeCoerce#
63 , dynTypeRep
77 , dynTypeRep
66--------------------------------------------------------------------------------
81--------------------------------------------------------------------------------
@@ -75,8 +90,11 @@ returnProcess = return
75bindProcess :: Process a -> (a -> Process b) -> Process b
90bindProcess :: Process a -> (a -> Process b) -> Process b
76bindProcess = (>>=)
91bindProcess = (>>=)
78−joinProcess :: Process (Process a) -> Process a
93+kleisliProcess :: (a -> Process b) -> (b -> Process c) -> a -> Process c
79−joinProcess = join
94+kleisliProcess = (>=>)
96+parJoinProcess :: Process (a -> Process b) -> a -> Process b
97+parJoinProcess proc a = proc >>= ($ a)
81---- Variations on standard or CH functions with an explicit dictionary arg ----
99---- Variations on standard or CH functions with an explicit dictionary arg ----
@@ -92,8 +110,8 @@ newChanDict SerializableDict = newChan
92---- Serialization dictionaries ------------------------------------------------
110---- Serialization dictionaries ------------------------------------------------
94-- | Specialized serialization dictionary required in 'cpBind'
112-- | Specialized serialization dictionary required in 'cpBind'
95−sdictBind :: SerializableDict (ByteString, ByteString)
113+sdictComp :: SerializableDict (ByteString, ByteString)
96−sdictBind = SerializableDict
114+sdictComp = SerializableDict
98---- Some specialised processes necessary to implement the combinators ---------
116---- Some specialised processes necessary to implement the combinators ---------
@@ -105,42 +123,54 @@ unClosure (Static label) env = do
105 Nothing -> fail "Derived.unClosure: resolveClosure failed"
123 Nothing -> fail "Derived.unClosure: resolveClosure failed"
106 Just dyn -> return dyn
124 Just dyn -> return dyn
126+-- | Work around a bug in Typeable
127+-- (http://hackage.haskell.org/trac/ghc/ticket/5692)
128+compareWithoutFingerprint :: TypeRep -> TypeRep -> Bool
129+compareWithoutFingerprint (TypeRep _ con ts) (TypeRep _ con' ts')
130+ = con == con' && all (uncurry compareWithoutFingerprint) (zip ts ts')
108-- | Remove a 'Dynamic' constructor, provided that the recorded type matches the
132-- | Remove a 'Dynamic' constructor, provided that the recorded type matches the
109-- type of the first static argument (the value of that argument is not used)
133-- type of the first static argument (the value of that argument is not used)
110unDynamic :: Static a -> Process Dynamic -> Process a
134unDynamic :: Static a -> Process Dynamic -> Process a
111unDynamic (Static label) pdyn = do
135unDynamic (Static label) pdyn = do
112 Dynamic typ val <- pdyn
136 Dynamic typ val <- pdyn
113− if typ == typeOfStaticLabel label
137+ if compareWithoutFingerprint typ (typeOfStaticLabel label) -- typ == typeOfStaticLabel label
114 then return (unsafeCoerce# val)
138 then return (unsafeCoerce# val)
115 else fail $ "unDynamic: cannot match "
139 else fail $ "unDynamic: cannot match "
116 ++ show typ
140 ++ show typ
117 ++ " against expected type "
141 ++ " against expected type "
118 ++ show (typeOfStaticLabel label)
142 ++ show (typeOfStaticLabel label)
120−-- | Dynamic bind
144+-- | Dynamic kleisli composition
122-- The first argument stops remotable from trying to generate a SerializableDict
146-- The first argument stops remotable from trying to generate a SerializableDict
123-- for (Process Dynamic, Process Dynamic)
147-- for (Process Dynamic, Process Dynamic)
124−bindDyn :: () -> (Process Dynamic, Process Dynamic) -> Process Dynamic
148+kleisliCompDyn :: () -> (Process Dynamic, Process Dynamic) -> Process Dynamic
125−bindDyn () (px, pf) = do
149+kleisliCompDyn () (pf, pg) = do
126− x <- px
150+ f <- pf -- a -> Process b
127− f <- pf
151+ g <- pg -- b -> Process c
128− case dynBind tyConProcess bindProcess x f of
152+ case dynKleisli tyConProcess kleisliProcess f g of
129 Just dyn -> return dyn
153 Just dyn -> return dyn
130− Nothing -> fail $ "bindDyn: could not bind "
154+ Nothing -> fail $ "kleisliCompDyn: could not compose "
131− ++ show (dynTypeRep x)
133 ++ show (dynTypeRep f)
155 ++ show (dynTypeRep f)
157+ ++ show (dynTypeRep g)
135 tyConProcess :: TyCon
159 tyConProcess :: TyCon
136 tyConProcess = typeRepTyCon (typeOf (undefined :: Process ()))
160 tyConProcess = typeRepTyCon (typeOf (undefined :: Process ()))
162+cpFirstAux :: (a -> Process b) -> (a, c) -> Process (b, c)
163+cpFirstAux f (a, c) = f a >>= \b -> return (b, c)
165+cpSecondAux :: (a -> Process b) -> (c, a) -> Process (c, b)
166+cpSecondAux f (c, a) = f a >>= \b -> return (c, b)
138---- Finally, the call to remotable --------------------------------------------
168---- Finally, the call to remotable --------------------------------------------
140remotable [ -- Monadic operations
170remotable [ -- Monadic operations
141 'returnProcess
171 'returnProcess
142 , 'bindProcess
172 , 'bindProcess
143− , 'joinProcess
173+ , 'parJoinProcess
144 -- CH primitives
174 -- CH primitives
146 , 'unlink
176 , 'unlink
@@ -149,13 +179,101 @@ remotable [ -- Monadic operations
149 , 'expectDict
179 , 'expectDict
150 , 'newChanDict
180 , 'newChanDict
151 -- Serialization dictionaries
181 -- Serialization dictionaries
152− , 'sdictBind
182+ , 'sdictComp
153 -- Specialized processes
183 -- Specialized processes
154 , 'unClosure
184 , 'unClosure
155 , 'unDynamic
185 , 'unDynamic
156− , 'bindDyn
186+ , 'kleisliCompDyn
191+--------------------------------------------------------------------------------
192+-- Some derived static functions --
193+--------------------------------------------------------------------------------
195+staticUndynamic :: Typeable a => Static (Process Dynamic -> Process a)
197+ $(mkStatic 'unDynamic) `staticApply` staticDuplicate (staticTypeOf (undefined :: a))
199+staticKleisliCompDyn :: Static ((Process Dynamic, Process Dynamic) -> Process Dynamic)
200+staticKleisliCompDyn = $(mkStatic 'kleisliCompDyn) `staticApply` staticUnit
202+--------------------------------------------------------------------------------
203+-- Definition of CP and the generalized arrow combinators --
204+--------------------------------------------------------------------------------
206+-- | 'CP a b' represents the closure of a process parameterized by 'a' and
207+-- returning 'b'. 'CP a b' forms a (restricted) generalized arrow
208+-- (<http://www.cs.berkeley.edu/~megacz/garrows/>)
209+type CP a b = Closure (a -> Process b)
211+-- | 'CP' introduction form
212+cpIntro :: forall a b. (Typeable a, Typeable b)
213+ => Closure (Process b) -> Closure (a -> Process b)
214+cpIntro (Closure static env) = Closure decoder env
216+ decoder :: Static (ByteString -> a -> Process b)
217+ decoder = staticConst `staticCompose` static
219+-- | 'CP' elimination form
220+cpElim :: forall a. Typeable a => CP () a -> Closure (Process a)
221+cpElim (Closure static env) = Closure decoder env
223+ decoder :: Static (ByteString -> Process a)
224+ decoder = staticFlip static `staticApply` staticUnit
226+-- | Identity ('Closure' version of 'return')
227+cpId :: Typeable a => CP a a
228+cpId = staticClosure $(mkStatic 'returnProcess)
230+-- | Left-to-right composition ('Closure' version of '>=>')
231+cpComp :: forall a b c. (Typeable a, Typeable b, Typeable c)
232+ => CP a b -> CP b c -> CP a c
233+cpComp (Closure fstatic fenv) (Closure gstatic genv) =
234+ Closure decoder (encode (fenv, genv))
236+ decoder :: Static (ByteString -> a -> Process c)
237+ decoder = $(mkStatic 'parJoinProcess)
241+ staticKleisliCompDyn
243+ (staticUnclosure fstatic `staticSplit` staticUnclosure gstatic)
245+ staticDecode $(mkStatic 'sdictComp)
248+cpFirst :: forall a b c. (Typeable a, Typeable b, Typeable c)
249+ => CP a b -> CP (a, c) (b, c)
250+cpFirst (Closure static env) = Closure decoder env
252+ decoder :: Static (ByteString -> (a, c) -> Process (b, c))
253+ decoder = $(mkStatic 'cpFirstAux) `staticCompose` static
256+cpSecond :: forall a b c. (Typeable a, Typeable b, Typeable c)
257+ => CP a b -> CP (c, a) (c, b)
258+cpSecond (Closure static env) = Closure decoder env
260+ decoder :: Static (ByteString -> (c, a) -> Process (c, b))
261+ decoder = $(mkStatic 'cpSecondAux) `staticCompose` static
263+-- | Split (Like 'Control.Arrow.***')
264+cpSplit :: (Typeable a, Typeable b, Typeable c, Typeable d)
265+ => CP a c -> CP b d -> CP (a, b) (c, d)
266+cpSplit f g = cpFirst f `cpComp` cpSecond g
268+-- | Left cancellation
269+cpCancelL :: Typeable a => CP ((), a) a
270+-- Closure (((), a) -> Process a)
271+cpCancelL = staticClosure ($(mkStatic 'returnProcess) `staticCompose` staticSnd)
273+-- | Right cancellation
274+cpCancelR :: Typeable a => CP (a, ()) a
275+cpCancelR = staticClosure ($(mkStatic 'returnProcess) `staticCompose` staticFst)
159--------------------------------------------------------------------------------
277--------------------------------------------------------------------------------
160-- Closure versions of CH primitives --
278-- Closure versions of CH primitives --
161--------------------------------------------------------------------------------
279--------------------------------------------------------------------------------
@@ -208,37 +326,11 @@ staticUnclosure :: Typeable a
208staticUnclosure s =
326staticUnclosure s =
209 $(mkStatic 'unClosure) `staticApply` staticDuplicate s
327 $(mkStatic 'unClosure) `staticApply` staticDuplicate s
211−staticUndynamic :: Typeable a => Static (Process Dynamic -> Process a)
213− $(mkStatic 'unDynamic) `staticApply` staticDuplicate (staticTypeOf (undefined :: a))
215−staticBindDyn :: Static ((Process Dynamic, Process Dynamic) -> Process Dynamic)
216−staticBindDyn = $(mkStatic 'bindDyn) `staticApply` staticUnit
218-- | Not-quite-monadic bind ('>>=')
329-- | Not-quite-monadic bind ('>>=')
219cpBind :: forall a b. (Typeable a, Typeable b)
330cpBind :: forall a b. (Typeable a, Typeable b)
220 => Closure (Process a) -> Closure (a -> Process b) -> Closure (Process b)
331 => Closure (Process a) -> Closure (a -> Process b) -> Closure (Process b)
221−cpBind (Closure xstatic xenv) (Closure fstatic fenv) =
332+cpBind x f = cpElim (cpIntro x `cpComp` f)
222− Closure decoder (encode (xenv, fenv))
224− decoder :: Static (ByteString -> Process b)
225− decoder = $(mkStatic 'joinProcess)
231− (staticUnclosure xstatic `staticSplit` staticUnclosure fstatic)
233− staticDecode $(mkStatic 'sdictBind)
235−cpIntro :: forall a b. (Typeable a, Typeable b)
236− => Closure (Process b) -> Closure (a -> Process b)
237−cpIntro (Closure static env) = Closure decoder env
239− decoder :: Static (ByteString -> a -> Process b)
240− decoder = staticConst `staticCompose` static
242-- | Monadic sequencing ('>>')
334-- | Monadic sequencing ('>>')
243cpSeq :: Closure (Process ()) -> Closure (Process ()) -> Closure (Process ())
335cpSeq :: Closure (Process ()) -> Closure (Process ()) -> Closure (Process ())
244cpSeq p q = p `cpBind` cpIntro q
336cpSeq p q = p `cpBind` cpIntro q