@@ -1,204 +1,338 @@
1-- | Derived (TH generated) closures
1-- | Derived (TH generated) closures
2+{-# LANGUAGE MagicHash #-}
2−module Control.Distributed.Process.Internal.Closure.Derived
3+module Control.Distributed.Process.Internal.Closure.Derived
3− ( remoteTable
4+ ( -- * Static functionals
10+ -- * Creating closures
4− -- * Process primitives
14+ -- * Closure versions of CH primitives
5− , linkClosure
15+ , cpLink
6− , unlinkClosure
16+ , cpUnlink
7− -- * Generic combinators
17+ , cpSend
8− , closureApply
18+ , cpExpect
9− , closureConst
19+ -- * @Closure (Process a)@ as a not-quite-monad
10− , closureUnit
20+ , cpReturn
11− -- * Arrow combinators for processes
29− -- * Derived process operators
32− -- * Serialization dictionaries
23+ -- * Serialization dictionaries (and their static versions)
33− , serializableDictUnit
24+ , sdictUnit
27+ , sdictProcessId__static
36−import Prelude hiding (lookup)
32+import Data.Binary (encode, decode)
37−import Data.Typeable (Typeable)
33+import Data.ByteString.Lazy (ByteString, empty)
38−import Data.Tuple (swap)
34+import Data.Typeable (Typeable, typeOf, TypeRep, typeRepTyCon, TyCon)
39import Control.Applicative ((<$>))
35import Control.Applicative ((<$>))
40−import Control.Monad ((>=>))
36+import Control.Monad (join)
37+import Control.Distributed.Process.Serializable (Serializable)
41import Control.Distributed.Process.Internal.Types
38import Control.Distributed.Process.Internal.Types
42− ( Closure(..)
39+ ( Closure(Closure)
40+ , SerializableDict(SerializableDict)
44− , RemoteTable
44+ , staticApply
45− , SerializableDict(..)
46 , ProcessId
45 , ProcessId
46+ , LocalNode(remoteTable)
48−import Control.Distributed.Process.Internal.TypeRep () -- Binary instances
49−import Control.Distributed.Process.Internal.Closure.TH (remotable, mkClosure)
50import Control.Distributed.Process.Internal.Primitives
49import Control.Distributed.Process.Internal.Primitives
54−import Control.Distributed.Process.Internal.Closure.BuiltIn (closureApply)
55+import Control.Distributed.Process.Internal.Closure.TH (remotable, mkStatic)
56+import Control.Distributed.Process.Internal.MessageT (getLocalNode)
57+import Control.Distributed.Process.Internal.Closure.Resolution (resolveClosure)
58+import Control.Distributed.Process.Internal.Dynamic
64+import qualified Control.Arrow as Arrow (first, second, (***))
56--------------------------------------------------------------------------------
66--------------------------------------------------------------------------------
57−-- TH stuff --
67+-- Setup: A number of functions that we will pass to 'remotable' --
58--------------------------------------------------------------------------------
68--------------------------------------------------------------------------------
60−idUnit :: () -> ()
70+---- Type specializations of monadic operations on Processes -------------------
63returnProcess :: a -> Process a
72returnProcess :: a -> Process a
64returnProcess = return
73returnProcess = return
66−kleisliComposeProcess :: (a -> Process b) -> (b -> Process c) -> a -> Process c
67−kleisliComposeProcess = (>=>)
69−firstProcess :: (a -> Process b) -> (a, c) -> Process (b, c)
75+bindProcess :: Process a -> (a -> Process b) -> Process b
70−firstProcess f (a, c) = f a >>= \b -> return (b, c)
76+bindProcess = (>>=)
72−swapProcess :: (a, b) -> Process (b, a)
78+joinProcess :: Process (Process a) -> Process a
73−swapProcess = return . swap
79+joinProcess = join
75−copyProcess :: a -> Process (a, a)
81+---- Functionals ---------------------------------------------------------------
76−copyProcess x = return (x, x)
82+
77−
83+compose :: (b -> c) -> (a -> b) -> a -> c
78−leftProcess :: (a -> Process b) -> Either a c -> Process (Either b c)
84+compose = (.)
79−leftProcess f (Left a) = Left <$> f a
85+
80−leftProcess _ (Right b) = Right <$> return b
86+first :: (a -> b) -> (a, c) -> (b, c)
81−
87+first = Arrow.first
82−mirrorProcess :: Either a b -> Process (Either b a)
88+
83−mirrorProcess (Left x) = Right <$> return x
89+second :: (a -> b) -> (c, a) -> (c, b)
84−mirrorProcess (Right y) = Left <$> return y
90+second = Arrow.second
86−untagProcess :: Either a a -> Process a
92+split :: (a -> b) -> (a' -> b') -> (a, a') -> (b, b')
87−untagProcess (Left x) = return x
93+split = (Arrow.***)
88−untagProcess (Right y) = return y
94+
89−
95+---- Variations on standard or CH functions with an explicit dictionary arg ----
97+decodeDict :: SerializableDict a -> ByteString -> a
98+decodeDict SerializableDict = decode
100+sendDict :: SerializableDict a -> ProcessId -> a -> Process ()
101+sendDict SerializableDict = send
90−serializableDictUnit :: SerializableDict ()
103+expectDict :: SerializableDict a -> Process a
104+expectDict SerializableDict = expect
106+---- Serialization dictionaries ------------------------------------------------
108+-- | Serialization dictionary for '()'
110+-- Use @$(mkStatic sdictUnit)@ (instead of 'sdictUnit__static')
111+-- to refer to the static dictionary.
112+sdictUnit :: SerializableDict ()
91−serializableDictUnit = SerializableDict
113+sdictUnit = SerializableDict
115+-- | Serialization dictionary for 'ProcessId'
117+-- Use @$(mkStatic sdictProcessId)@ (instead of 'sdictProcessId__static')
118+-- to refer to the static dictionary.
119+sdictProcessId :: SerializableDict ProcessId
120+sdictProcessId = SerializableDict
122+-- | Specialized serialization dictionary required in 'cpBind'
123+sdictBind :: SerializableDict (((StaticLabel, ByteString), (StaticLabel, ByteString)), TypeRep)
124+sdictBind = SerializableDict
126+---- Some specialised processes necessary to implement the combinators ---------
128+unClosure :: (StaticLabel, ByteString) -> Process Dynamic
129+unClosure (label, env) = do
130+ rtable <- remoteTable <$> procMsg getLocalNode
131+ case resolveClosure rtable label env of
132+ Nothing -> fail "Derived.unClosure: resolveClosure failed"
133+ Just dyn -> return dyn
135+unDynamic :: (Process Dynamic, TypeRep) -> Process a
136+unDynamic (pdyn, typ) = do
137+ Dynamic typ' val <- pdyn
139+ then return (unsafeCoerce# val)
140+ else fail $ "unDynamic: cannot match "
142+ ++ " against expected type "
145+bindDyn :: (Process Dynamic, Process Dynamic) -> Process Dynamic
146+bindDyn (px, pf) = do
149+ case dynBind tyConProcess bindProcess x f of
150+ Just dyn -> return dyn
151+ Nothing -> fail $ "bindDyn: could not bind "
152+ ++ show (dynTypeRep x)
154+ ++ show (dynTypeRep f)
156+ tyConProcess :: TyCon
157+ tyConProcess = typeRepTyCon (typeOf (undefined :: Process ()))
159+---- Finally, the call to remotable --------------------------------------------
93−remotable [ 'const
161+remotable [ -- Monadic operations
95− , 'returnProcess
162+ 'returnProcess
96− , 'kleisliComposeProcess
163+ , 'bindProcess
97− , 'firstProcess
164+ , 'joinProcess
98− , 'swapProcess
165+ -- Functionals (predefined)
99− , 'copyProcess
166+ , 'const
100− , 'leftProcess
167+ -- Functionals (defined above)
101− , 'mirrorProcess
168+ , 'compose
102− , 'untagProcess
169+ , 'first
104 , 'unlink
174 , 'unlink
105− , 'serializableDictUnit
175+ -- Explicit dictionaries
179+ -- Serialization dictionaries
183+ -- Specialized processes
108−remoteTable :: RemoteTable -> RemoteTable
109−remoteTable = __remoteTable
111--------------------------------------------------------------------------------
189--------------------------------------------------------------------------------
112−-- Process primitives --
190+-- Static versions of the functionals --
191+-- (We give these explicit names because they are useful outside this module) --
113--------------------------------------------------------------------------------
192--------------------------------------------------------------------------------
115−-- | Closure version of 'link'
194+-- | Static version of 'const'
116−linkClosure :: ProcessId -> Closure (Process ())
195+staticConst :: (Typeable a, Typeable b) => Static (a -> b -> a)
117−linkClosure = $(mkClosure 'link)
196+staticConst = $(mkStatic 'const)
119−-- | Closure version of 'unlink'
198+-- | Static version of ('Prelude..')
120−unlinkClosure :: ProcessId -> Closure (Process ())
199+staticCompose :: (Typeable a, Typeable b, Typeable c)
121−unlinkClosure = $(mkClosure 'unlink)
200+ => Static (b -> c) -> Static (a -> b) -> Static (a -> c)
201+staticCompose f x = $(mkStatic 'compose) `staticApply` f `staticApply` x
123−--------------------------------------------------------------------------------
203+-- | Static version of 'Control.Arrow.first'
124−-- Generic closure combinators --
204+staticFirst :: (Typeable a, Typeable b, Typeable c)
125−--------------------------------------------------------------------------------
205+ => Static ((a -> b) -> (a, c) -> (b, c))
206+staticFirst = $(mkStatic 'first)
208+-- | Static version of 'Control.Arrow.second'
127−closureConst :: (Typeable a, Typeable b) => Closure (a -> b -> a)
209+staticSecond :: (Typeable a, Typeable b, Typeable c)
128−closureConst = $(mkClosure 'const)
210+ => Static ((a -> b) -> (c, a) -> (c, b))
211+staticSecond = $(mkStatic 'second)
130−closureUnit :: Closure ()
213+-- | Static version of ('Control.Arrow.***')
131−closureUnit = $(mkClosure 'idUnit) ()
214+staticSplit :: (Typeable a, Typeable b, Typeable c, Typeable d)
215+ => Static (a -> c) -> Static (b -> d) -> Static ((a, b) -> (c, d))
216+staticSplit f g = $(mkStatic 'split) `staticApply` f `staticApply` g
133--------------------------------------------------------------------------------
218--------------------------------------------------------------------------------
134−-- Arrow combinators for processes --
219+-- Creating closures --
135--------------------------------------------------------------------------------
220--------------------------------------------------------------------------------
137−type CP a b = Closure (a -> Process b)
222+staticDecode :: Typeable a => Static (SerializableDict a) -> Static (ByteString -> a)
138−
223+staticDecode dict = $(mkStatic 'decodeDict) `staticApply` dict
139−cpIntro :: (Typeable a, Typeable b)
140− => Closure (Process b) -> CP a b
141−cpIntro = closureApply closureConst
143−cpElim :: Typeable a
225+staticClosure :: forall a. Typeable a => Static a -> Closure a
144− => CP () a -> Closure (Process a)
226+staticClosure static = Closure decoder empty
145−cpElim = flip closureApply closureUnit
227+ where
228+ decoder :: Static (ByteString -> a)
229+ decoder = staticConst `staticApply` static
147−cpId :: Typeable a => CP a a
231+toClosure :: forall a. Serializable a
148−cpId = $(mkClosure 'returnProcess)
232+ => Static (SerializableDict a) -> a -> Closure a
233+toClosure dict x = Closure decoder (encode x)
235+ decoder :: Static (ByteString -> a)
236+ decoder = $(mkStatic 'decodeDict) `staticApply` dict
150−cpComp :: (Typeable a, Typeable b, Typeable c) => CP a b -> CP b c -> CP a c
238+--------------------------------------------------------------------------------
151−cpComp f g = $(mkClosure 'kleisliComposeProcess) `closureApply` f `closureApply` g
239+-- Closure versions of CH primitives --
152−
240+--------------------------------------------------------------------------------
153−cpFirst :: (Typeable a, Typeable b, Typeable c) => CP a b -> CP (a, c) (b, c)
154−cpFirst = closureApply $(mkClosure 'firstProcess)
156−cpSwap :: (Typeable a, Typeable b) => CP (a, b) (b, a)
157−cpSwap = $(mkClosure 'swapProcess)
159−cpSecond :: (Typeable a, Typeable b, Typeable c) => CP a b -> CP (c, a) (c, b)
160−cpSecond f = cpSwap `cpComp` cpFirst f `cpComp` cpSwap
162−cpPair :: (Typeable a, Typeable a', Typeable b, Typeable b')
163− => CP a b -> CP a' b' -> CP (a, a') (b, b')
164−cpPair f g = cpFirst f `cpComp` cpSecond g
166−cpCopy :: Typeable a => CP a (a, a)
167−cpCopy = $(mkClosure 'copyProcess)
169−cpFanOut :: (Typeable a, Typeable b, Typeable c)
170− => CP a b -> CP a c -> CP a (b, c)
171−cpFanOut f g = cpCopy `cpComp` (f `cpPair` g)
173−cpLeft :: (Typeable a, Typeable b, Typeable c)
174− => CP a b -> CP (Either a c) (Either b c)
175−cpLeft = closureApply $(mkClosure 'leftProcess)
177−cpMirror :: (Typeable a, Typeable b) => CP (Either a b) (Either b a)
178−cpMirror = $(mkClosure 'mirrorProcess)
180−cpRight :: (Typeable a, Typeable b, Typeable c)
181− => CP a b -> CP (Either c a) (Either c b)
182−cpRight f = cpMirror `cpComp` cpLeft f `cpComp` cpMirror
184−cpEither :: (Typeable a, Typeable a', Typeable b, Typeable b')
185− => CP a b -> CP a' b' -> CP (Either a a') (Either b b')
186−cpEither f g = cpLeft f `cpComp` cpRight g
188−cpUntag :: Typeable a => CP (Either a a) a
242+-- | Closure version of 'link'
189−cpUntag = $(mkClosure 'untagProcess)
243+cpLink :: ProcessId -> Closure (Process ())
244+cpLink pid = Closure decoder (encode pid)
246+ decoder :: Static (ByteString -> Process ())
247+ decoder = $(mkStatic 'link)
249+ ($(mkStatic 'decodeDict) `staticApply` $(mkStatic 'sdictProcessId))
191−cpFanIn :: (Typeable a, Typeable b, Typeable c)
251+-- | Closure version of 'unlink'
192− => CP a c -> CP b c -> CP (Either a b) c
252+cpUnlink :: ProcessId -> Closure (Process ())
193−cpFanIn f g = (f `cpEither` g) `cpComp` cpUntag
253+cpUnlink pid = Closure decoder (encode pid)
255+ decoder :: Static (ByteString -> Process ())
256+ decoder = $(mkStatic 'unlink)
258+ ($(mkStatic 'decodeDict) `staticApply` $(mkStatic 'sdictProcessId))
260+-- | Closure version of 'send'
261+cpSend :: forall a. Typeable a
262+ => Static (SerializableDict a) -> ProcessId -> Closure (a -> Process ())
263+cpSend dict pid = Closure decoder (encode pid)
265+ decoder :: Static (ByteString -> a -> Process ())
266+ decoder = ($(mkStatic 'sendDict) `staticApply` dict)
268+ ($(mkStatic 'decodeDict) `staticApply` $(mkStatic 'sdictProcessId))
270+-- | Closure version of 'expect'
271+cpExpect :: Typeable a => Static (SerializableDict a) -> Closure (Process a)
272+cpExpect dict = staticClosure ($(mkStatic 'expectDict) `staticApply` dict)
195--------------------------------------------------------------------------------
274--------------------------------------------------------------------------------
196−-- Some derived operators for processes --
275+-- (Closure . Process) as a not-quite-monad --
197--------------------------------------------------------------------------------
276--------------------------------------------------------------------------------
278+-- | Not-quite-monadic 'return'
279+cpReturn :: forall a. Serializable a
280+ => Static (SerializableDict a) -> a -> Closure (Process a)
281+cpReturn dict x = Closure decoder (encode x)
283+ decoder :: Static (ByteString -> Process a)
284+ decoder = $(mkStatic 'returnProcess)
286+ ($(mkStatic 'decodeDict) `staticApply` dict)
288+-- | Not-quite-monadic bind ('>>=')
199−cpBind :: (Typeable a, Typeable b)
289+cpBind :: forall a b. Typeable b
200 => Closure (Process a) -> Closure (a -> Process b) -> Closure (Process b)
290 => Closure (Process a) -> Closure (a -> Process b) -> Closure (Process b)
201−cpBind x f = cpElim $ cpIntro x `cpComp` f
291+cpBind (Closure (Static xlabel) xenv) (Closure (Static flabel) fenv) =
202−
292+ let env :: (((StaticLabel, ByteString), (StaticLabel, ByteString)), TypeRep)
293+ env = (((xlabel, xenv), (flabel, fenv)), typeOf (undefined :: Process b))
294+ in Closure decoder (encode env)
296+ decoder :: Static (ByteString -> Process b)
305+ aux1 :: Static (ByteString -> (((StaticLabel, ByteString), (StaticLabel, ByteString)), TypeRep))
306+ aux1 = $(mkStatic 'decodeDict) `staticApply` $(mkStatic 'sdictBind)
308+ aux2 :: Static ((StaticLabel, ByteString) -> Process Dynamic)
309+ aux2 = $(mkStatic 'unClosure)
311+ aux3 :: Static (((StaticLabel, ByteString), (StaticLabel, ByteString)) -> (Process Dynamic, Process Dynamic))
312+ aux3 = aux2 `staticSplit` aux2
314+ aux4 :: Static ((Process Dynamic, Process Dynamic) -> Process Dynamic)
315+ aux4 = $(mkStatic 'bindDyn)
317+ aux5 :: Static (((StaticLabel, ByteString), (StaticLabel, ByteString)) -> Process Dynamic)
318+ aux5 = aux4 `staticCompose` aux3
320+ aux6 :: Static ((((StaticLabel, ByteString), (StaticLabel, ByteString)), TypeRep) -> (Process Dynamic, TypeRep))
321+ aux6 = staticFirst `staticApply` aux5
323+ aux7 :: Static ((Process Dynamic, TypeRep) -> Process (Process b))
324+ aux7 = $(mkStatic 'unDynamic)
326+ aux8 :: Static (Process (Process b) -> Process b)
327+ aux8 = $(mkStatic 'joinProcess)
329+cpIntro :: forall a b. (Typeable a, Typeable b)
330+ => Closure (Process b) -> Closure (a -> Process b)
331+cpIntro (Closure static env) = Closure decoder env
333+ decoder :: Static (ByteString -> a -> Process b)
334+ decoder = staticConst `staticCompose` static
336+-- | Monadic sequencing ('>>')
203cpSeq :: Closure (Process ()) -> Closure (Process ()) -> Closure (Process ())
337cpSeq :: Closure (Process ()) -> Closure (Process ()) -> Closure (Process ())
204cpSeq p q = p `cpBind` cpIntro q
338cpSeq p q = p `cpBind` cpIntro q