git.iko.soy/distributed-process
on master help sign in
First steps towards extracting static
7b5c530Edsko de Vries
distributed-process/distributed-process.cabal+7−8
@@ -43,21 +43,18 @@ Library
43 time >= 1.2 && < 1.5,
43 time >= 1.2 && < 1.5,
44 template-haskell >= 2.6 && < 2.8,
44 template-haskell >= 2.6 && < 2.8,
45 random >= 1.0 && < 1.1,
45 random >= 1.0 && < 1.1,
46− ghc-prim >= 0.2 && < 0.3
46+ ghc-prim >= 0.2 && < 0.3,
47+ distributed-static >= 0.1 && < 0.2
47 Exposed-modules: Control.Distributed.Process,
48 Exposed-modules: Control.Distributed.Process,
48 Control.Distributed.Process.Serializable,
49 Control.Distributed.Process.Serializable,
49 Control.Distributed.Process.Closure,
50 Control.Distributed.Process.Closure,
50 Control.Distributed.Process.Node,
51 Control.Distributed.Process.Node,
51 Control.Distributed.Process.Internal.Primitives,
52 Control.Distributed.Process.Internal.Primitives,
52 Control.Distributed.Process.Internal.CQueue,
53 Control.Distributed.Process.Internal.CQueue,
53− Control.Distributed.Process.Internal.Dynamic,
54− Control.Distributed.Process.Internal.TypeRep,
55 Control.Distributed.Process.Internal.Types,
54 Control.Distributed.Process.Internal.Types,
56− Control.Distributed.Process.Internal.Closure.Static,
57 Control.Distributed.Process.Internal.Closure.MkClosure,
55 Control.Distributed.Process.Internal.Closure.MkClosure,
58− Control.Distributed.Process.Internal.Closure.CP,
59 Control.Distributed.Process.Internal.Closure.TH,
56 Control.Distributed.Process.Internal.Closure.TH,
60− Control.Distributed.Process.Internal.Closure.Resolution,
57+ Control.Distributed.Process.Internal.Closure.BuiltIn,
61 Control.Distributed.Process.Internal.Node
58 Control.Distributed.Process.Internal.Node
62 Extensions: RankNTypes,
59 Extensions: RankNTypes,
63 ScopedTypeVariables,
60 ScopedTypeVariables,
@@ -90,7 +87,8 @@ Test-Suite TestCH
90 template-haskell >= 2.6 && < 2.8,
87 template-haskell >= 2.6 && < 2.8,
91 random >= 1.0 && < 1.1,
88 random >= 1.0 && < 1.1,
92 ghc-prim >= 0.2 && < 0.3,
89 ghc-prim >= 0.2 && < 0.3,
93− ansi-terminal >= 0.5 && < 0.6
90+ ansi-terminal >= 0.5 && < 0.6,
91+ distributed-static >= 0.1 && < 0.2
94 Extensions: RankNTypes,
92 Extensions: RankNTypes,
95 ScopedTypeVariables,
93 ScopedTypeVariables,
96 FlexibleInstances,
94 FlexibleInstances,
@@ -122,7 +120,8 @@ Test-Suite TestClosure
122 template-haskell >= 2.6 && < 2.8,
120 template-haskell >= 2.6 && < 2.8,
123 random >= 1.0 && < 1.1,
121 random >= 1.0 && < 1.1,
124 ghc-prim >= 0.2 && < 0.3,
122 ghc-prim >= 0.2 && < 0.3,
125− ansi-terminal >= 0.5 && < 0.6
123+ ansi-terminal >= 0.5 && < 0.6,
124+ distributed-static >= 0.1 && < 0.2
126 Other-modules: TestAuxiliary
125 Other-modules: TestAuxiliary
127 Extensions: RankNTypes,
126 Extensions: RankNTypes,
128 ScopedTypeVariables,
127 ScopedTypeVariables,
distributed-process/src/Control/Distributed/Process.hs+37−18
@@ -100,7 +100,6 @@ module Control.Distributed.Process
100 , spawnChannelLocal
100 , spawnChannelLocal
101 ) where
101 ) where
102
102
103−
104#if ! MIN_VERSION_base(4,6,0)
103#if ! MIN_VERSION_base(4,6,0)
105import Prelude hiding (catch)
104import Prelude hiding (catch)
106#endif
105#endif
@@ -109,13 +108,15 @@ import Data.Typeable (Typeable)
109import Control.Monad.IO.Class (liftIO)
108import Control.Monad.IO.Class (liftIO)
110import Control.Applicative ((<$>))
109import Control.Applicative ((<$>))
111import Control.Monad.Reader (ask)
110import Control.Monad.Reader (ask)
111+import Control.Distributed.Static
112+ ( Closure(..)
113+ , Static
114+ , RemoteTable
115+ )
112import Control.Distributed.Process.Internal.Types
116import Control.Distributed.Process.Internal.Types
113− ( RemoteTable
114− , NodeId(..)
117+ ( NodeId(..)
115 , ProcessId(..)
118 , ProcessId(..)
116 , Process(..)
119 , Process(..)
117− , Closure(..)
118− , Static
119 , MonitorRef(..)
120 , MonitorRef(..)
120 , ProcessMonitorNotification(..)
121 , ProcessMonitorNotification(..)
121 , NodeMonitorNotification(..)
122 , NodeMonitorNotification(..)
@@ -126,17 +127,32 @@ import Control.Distributed.Process.Internal.Types
126 , DiedReason(..)
127 , DiedReason(..)
127 , SpawnRef(..)
128 , SpawnRef(..)
128 , DidSpawn(..)
129 , DidSpawn(..)
129− , Closure(..)
130 , SendPort(..)
130 , SendPort(..)
131 , ReceivePort(..)
131 , ReceivePort(..)
132− , SerializableDict(..)
133 , SendPortId(..)
132 , SendPortId(..)
134 , WhereIsReply(..)
133 , WhereIsReply(..)
135 , LocalProcess(processNode)
134 , LocalProcess(processNode)
136 )
135 )
136+import Control.Distributed.Process.Serializable (SerializableDict)
137+import Control.Distributed.Process.Internal.Closure.BuiltIn
138+ ( sdictUnit
139+ , sdictSendPort
140+ , idCP
141+ , seqCP
142+ , bindCP
143+ , splitCP
144+ , cpLink
145+ , cpUnlink
146+ , cpExpect
147+ , cpSend
148+ , cpNewChan
149+ )
150+import Control.Distributed.Static (closureCompose, sndStatic, staticClosure)
151+
152+{-
137import Control.Distributed.Process.Internal.Closure.CP
153import Control.Distributed.Process.Internal.Closure.CP
138− ( cpSeq
154+ (
139− , cpBind
155+ , bindCP
140 , cpSend
156 , cpSend
141 , cpExpect
157 , cpExpect
142 , cpLink
158 , cpLink
@@ -145,10 +161,13 @@ import Control.Distributed.Process.Internal.Closure.CP
145 , cpCancelL
161 , cpCancelL
146 , cpSplit
162 , cpSplit
147 )
163 )
164+-}
165+{-
148import Control.Distributed.Process.Internal.Closure.Static
166import Control.Distributed.Process.Internal.Closure.Static
149 ( sdictUnit
167 ( sdictUnit
150 , sdictSendPort
168 , sdictSendPort
151 )
169 )
170+-}
152import Control.Distributed.Process.Internal.Primitives
171import Control.Distributed.Process.Internal.Primitives
153 ( -- Basic messaging
172 ( -- Basic messaging
154 send
173 send
@@ -289,9 +308,9 @@ spawn nid proc = do
289 -- that was already set up
308 -- that was already set up
290 mRef <- monitorNode nid
309 mRef <- monitorNode nid
291 sRef <- spawnAsync nid $ cpLink us
310 sRef <- spawnAsync nid $ cpLink us
292− `cpSeq` cpExpect sdictUnit
311+ `seqCP` cpExpect sdictUnit
293− `cpSeq` cpUnlink us
312+ `seqCP` cpUnlink us
294− `cpSeq` proc
313+ `seqCP` proc
295 mPid <- receiveWait
314 mPid <- receiveWait
296 [ matchIf (\(DidSpawn ref _) -> ref == sRef)
315 [ matchIf (\(DidSpawn ref _) -> ref == sRef)
297 (\(DidSpawn _ pid) -> return $ Just pid)
316 (\(DidSpawn _ pid) -> return $ Just pid)
@@ -333,7 +352,7 @@ spawnMonitor nid proc = do
333call :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (Process a) -> Process a
352call :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (Process a) -> Process a
334call dict nid proc = do
353call dict nid proc = do
335 us <- getSelfPid
354 us <- getSelfPid
336− (_, mRef) <- spawnMonitor nid (proc `cpBind` cpSend dict us)
355+ (_, mRef) <- spawnMonitor nid (proc `bindCP` cpSend dict us)
337 -- We are guaranteed to receive the reply before the monitor notification
356 -- We are guaranteed to receive the reply before the monitor notification
338 -- (if a reply is sent at all)
357 -- (if a reply is sent at all)
339 -- NOTE: This might not be true if we switch to unreliable delivery.
358 -- NOTE: This might not be true if we switch to unreliable delivery.
@@ -353,7 +372,7 @@ spawnSupervised :: NodeId
353 -> Process (ProcessId, MonitorRef)
372 -> Process (ProcessId, MonitorRef)
354spawnSupervised nid proc = do
373spawnSupervised nid proc = do
355 us <- getSelfPid
374 us <- getSelfPid
356− them <- spawn nid (cpLink us `cpSeq` proc)
375+ them <- spawn nid (cpLink us `seqCP` proc)
357 ref <- monitor them
376 ref <- monitor them
358 return (them, ref)
377 return (them, ref)
359
378
@@ -370,10 +389,10 @@ spawnChannel dict nid proc = do
370 where
389 where
371 go :: ProcessId -> Closure (Process ())
390 go :: ProcessId -> Closure (Process ())
372 go pid = cpNewChan dict
391 go pid = cpNewChan dict
373− `cpBind`
392+ `bindCP`
374− (cpSend (sdictSendPort dict) pid `cpSplit` proc)
393+ (cpSend (sdictSendPort dict) pid `splitCP` proc)
375− `cpBind`
394+ `bindCP`
376− cpCancelL
395+ (idCP `closureCompose` staticClosure sndStatic)
377
396
378--------------------------------------------------------------------------------
397--------------------------------------------------------------------------------
379-- Local versions of spawn --
398-- Local versions of spawn --
distributed-process/src/Control/Distributed/Process/Closure.hs+78−28
@@ -228,37 +228,32 @@ module Control.Distributed.Process.Closure
228 -- * Primitive operations on static values
228 -- * Primitive operations on static values
229 , staticApply
229 , staticApply
230 , staticDuplicate
230 , staticDuplicate
231− -- * Static functionals
231+ -- * Static values
232− , staticConst
232+ , idStatic
233− , staticFlip
233+ , composeStatic
234− , staticFst
234+ , constStatic
235− , staticSnd
235+ , flipStatic
236+ , fstStatic
237+ , sndStatic
238+ , firstStatic
239+ , secondStatic
240+ , splitStatic
241+ , unitStatic
242+ -- * Combinators on static values
236 , staticCompose
243 , staticCompose
237− , staticFirst
238− , staticSecond
239− , staticSplit
240− -- * Static constants
241− , staticUnit
242− -- * Creating closures
243− , staticDecode
244− , staticClosure
245− , toClosure
246 -- * Serialization dictionaries (and their static versions)
244 -- * Serialization dictionaries (and their static versions)
247 , SerializableDict(..)
245 , SerializableDict(..)
248 , sdictUnit
246 , sdictUnit
249 , sdictProcessId
247 , sdictProcessId
250 , sdictSendPort
248 , sdictSendPort
249+ -- * Creating closures
250+ , staticDecode
251+ , staticClosure
252+-- , toClosure
251 -- * Definition of CP and the generalized arrow combinators
253 -- * Definition of CP and the generalized arrow combinators
252 , CP
254 , CP
253− , cpIntro
255+ , idCP
254− , cpElim
256+ , splitCP
255− , cpId
256− , cpComp
257− , cpFirst
258− , cpSecond
259− , cpSplit
260− , cpCancelL
261− , cpCancelR
262 -- * Closure versions of CH primitives
257 -- * Closure versions of CH primitives
263 , cpLink
258 , cpLink
264 , cpUnlink
259 , cpUnlink
@@ -266,22 +261,72 @@ module Control.Distributed.Process.Closure
266 , cpExpect
261 , cpExpect
267 , cpNewChan
262 , cpNewChan
268 -- * @Closure (Process a)@ as a not-quite-monad
263 -- * @Closure (Process a)@ as a not-quite-monad
269− , cpReturn
264+ , returnCP
270− , cpBind
265+ , bindCP
271− , cpSeq
266+ , seqCP
272 ) where
267 ) where
273
268
269+import Control.Distributed.Process.Serializable (SerializableDict(..))
270+
271+import Control.Distributed.Static
272+ ( -- Introducing static values
273+ staticApply
274+ , staticDuplicate
275+ -- Static values
276+ , idStatic
277+ , composeStatic
278+ , constStatic
279+ , flipStatic
280+ , fstStatic
281+ , sndStatic
282+ , firstStatic
283+ , secondStatic
284+ , splitStatic
285+ , unitStatic
286+ -- Combinators on static values
287+ , staticCompose
288+ , staticClosure
289+ , closureSplit
290+ )
291+
292+
293+{-
274import Control.Distributed.Process.Internal.Types
294import Control.Distributed.Process.Internal.Types
275− ( SerializableDict(..)
276− , staticApply
295+ ( staticApply
277 , staticDuplicate
296 , staticDuplicate
278 )
297 )
298+-}
299+
279import Control.Distributed.Process.Internal.Closure.TH
300import Control.Distributed.Process.Internal.Closure.TH
280 ( remotable
301 ( remotable
281 , mkStatic
302 , mkStatic
282 , functionSDict
303 , functionSDict
283 , functionTDict
304 , functionTDict
284 )
305 )
306+import Control.Distributed.Process.Internal.Closure.BuiltIn
307+ ( -- Remote table
308+ remoteTable
309+ -- Static dictionaries and associated operations
310+ , staticDecode
311+ , sdictUnit
312+ , sdictProcessId
313+ , sdictSendPort
314+ -- The CP type and associated combinators
315+ , CP
316+ , splitCP
317+ , idCP
318+ , returnCP
319+ , seqCP
320+ , bindCP
321+ -- CP versions of Cloud Haskell primitives
322+ , cpLink
323+ , cpUnlink
324+ , cpSend
325+ , cpExpect
326+ , cpNewChan
327+ )
328+
329+{-
285import Control.Distributed.Process.Internal.Closure.Static
330import Control.Distributed.Process.Internal.Closure.Static
286 ( -- Static functionals
331 ( -- Static functionals
287 staticConst
332 staticConst
@@ -303,7 +348,11 @@ import Control.Distributed.Process.Internal.Closure.Static
303 , sdictProcessId
348 , sdictProcessId
304 , sdictSendPort
349 , sdictSendPort
305 )
350 )
351+-}
352+
306import Control.Distributed.Process.Internal.Closure.MkClosure (mkClosure)
353import Control.Distributed.Process.Internal.Closure.MkClosure (mkClosure)
354+
355+{-
307import Control.Distributed.Process.Internal.Closure.CP
356import Control.Distributed.Process.Internal.Closure.CP
308 ( -- Definition of CP and the generalized arrow combinators
357 ( -- Definition of CP and the generalized arrow combinators
309 CP
358 CP
@@ -327,3 +376,4 @@ import Control.Distributed.Process.Internal.Closure.CP
327 , cpBind
376 , cpBind
328 , cpSeq
377 , cpSeq
329 )
378 )
379+-}
distributed-process/src/Control/Distributed/Process/Internal/Closure/CP.hsdeleted−330
@@ -1,330 +0,0 @@
1−-- | Combinator for process closures
2−{-# LANGUAGE MagicHash #-}
3−module Control.Distributed.Process.Internal.Closure.CP
4− ( -- * Definition of CP and the generalized arrow combinators
5− CP
6− , cpIntro
7− , cpElim
8− , cpId
9− , cpComp
10− , cpFirst
11− , cpSecond
12− , cpSplit
13− , cpCancelL
14− , cpCancelR
15− -- * Closure versions of CH primitives
16− , cpLink
17− , cpUnlink
18− , cpSend
19− , cpExpect
20− , cpNewChan
21− -- * @Closure (Process a)@ as a not-quite-monad
22− , cpReturn
23− , cpBind
24− , cpSeq
25− -- * Runtime support
26− , __remoteTable
27− ) where
28−
29−import Data.Binary (encode)
30−import Data.ByteString.Lazy (ByteString)
31−import Data.Typeable (Typeable, typeOf, typeRepTyCon, TyCon)
32−import Control.Applicative ((<$>))
33−import Control.Monad ((>=>))
34−import Control.Monad.Reader (ask)
35−import Control.Distributed.Process.Serializable (Serializable)
36−import Control.Distributed.Process.Internal.Types
37− ( Closure(Closure)
38− , SerializableDict(SerializableDict)
39− , Static(Static)
40− , Process
41− , staticApply
42− , staticDuplicate
43− , staticTypeOf
44− , typeOfStaticLabel
45− , ProcessId
46− , LocalNode(remoteTable)
47− , LocalProcess(processNode)
48− , SendPort
49− , ReceivePort
50− )
51−import Control.Distributed.Process.Internal.Primitives
52− ( link
53− , unlink
54− , send
55− , expect
56− , newChan
57− )
58−import Control.Distributed.Process.Internal.Closure.TH (remotable, mkStatic)
59−import Control.Distributed.Process.Internal.Closure.Resolution (resolveClosure)
60−import Control.Distributed.Process.Internal.Closure.Static
61− ( staticCompose
62− , staticDecode
63− , staticClosure
64− , staticSplit
65− , staticConst
66− , staticUnit
67− , staticFlip
68− , staticFst
69− , staticSnd
70− , sdictProcessId
71− )
72−import Control.Distributed.Process.Internal.Closure.MkClosure (mkClosure)
73−import Control.Distributed.Process.Internal.Dynamic
74− ( Dynamic(Dynamic)
75− , unsafeCoerce#
76− , dynTypeRep
77− , dynKleisli
78− )
79−import Control.Distributed.Process.Internal.TypeRep (compareTypeRep)
80−
81−--------------------------------------------------------------------------------
82−-- Setup: A number of functions that we will pass to 'remotable' --
83−--------------------------------------------------------------------------------
84−
85−---- Type specializations of monadic operations on Processes -------------------
86−
87−returnProcess :: a -> Process a
88−returnProcess = return
89−
90−bindProcess :: Process a -> (a -> Process b) -> Process b
91−bindProcess = (>>=)
92−
93−kleisliProcess :: (a -> Process b) -> (b -> Process c) -> a -> Process c
94−kleisliProcess = (>=>)
95−
96−parJoinProcess :: Process (a -> Process b) -> a -> Process b
97−parJoinProcess proc a = proc >>= ($ a)
98−
99−---- Variations on standard or CH functions with an explicit dictionary arg ----
100−
101−sendDict :: SerializableDict a -> ProcessId -> a -> Process ()
102−sendDict SerializableDict = send
103−
104−expectDict :: SerializableDict a -> Process a
105−expectDict SerializableDict = expect
106−
107−newChanDict :: SerializableDict a -> Process (SendPort a, ReceivePort a)
108−newChanDict SerializableDict = newChan
109−
110−---- Serialization dictionaries ------------------------------------------------
111−
112−-- | Specialized serialization dictionary required in 'cpBind'
113−sdictComp :: SerializableDict (ByteString, ByteString)
114−sdictComp = SerializableDict
115−
116−---- Some specialised processes necessary to implement the combinators ---------
117−
118−-- | Resolve a closure
119−unClosure :: Static a -> ByteString -> Process Dynamic
120−unClosure static env = do
121− rtable <- remoteTable . processNode <$> ask
122− case resolveClosure rtable static env of
123− Nothing -> fail "Derived.unClosure: resolveClosure failed"
124− Just dyn -> return dyn
125−
126−-- | Remove a 'Dynamic' constructor, provided that the recorded type matches the
127−-- type of the first static argument (the value of that argument is not used)
128−unDynamic :: Static a -> Process Dynamic -> Process a
129−unDynamic (Static label) pdyn = do
130− Dynamic typ val <- pdyn
131− if typ `compareTypeRep` typeOfStaticLabel label
132− then return (unsafeCoerce# val)
133− else fail $ "unDynamic: cannot match "
134− ++ show typ
135− ++ " against expected type "
136− ++ show (typeOfStaticLabel label)
137−
138−-- | Dynamic kleisli composition
139−--
140−-- The first argument stops remotable from trying to generate a SerializableDict
141−-- for (Process Dynamic, Process Dynamic)
142−kleisliCompDyn :: () -> (Process Dynamic, Process Dynamic) -> Process Dynamic
143−kleisliCompDyn () (pf, pg) = do
144− f <- pf -- a -> Process b
145− g <- pg -- b -> Process c
146− case dynKleisli tyConProcess kleisliProcess f g of
147− Just dyn -> return dyn
148− Nothing -> fail $ "kleisliCompDyn: could not compose "
149− ++ show (dynTypeRep f)
150− ++ " with "
151− ++ show (dynTypeRep g)
152− where
153− tyConProcess :: TyCon
154− tyConProcess = typeRepTyCon (typeOf (undefined :: Process ()))
155−
156−cpFirstAux :: (a -> Process b) -> (a, c) -> Process (b, c)
157−cpFirstAux f (a, c) = f a >>= \b -> return (b, c)
158−
159−cpSecondAux :: (a -> Process b) -> (c, a) -> Process (c, b)
160−cpSecondAux f (c, a) = f a >>= \b -> return (c, b)
161−
162−---- Finally, the call to remotable --------------------------------------------
163−
164−remotable [ -- Monadic operations
165− 'returnProcess
166− , 'bindProcess
167− , 'parJoinProcess
168− -- CH primitives
169− , 'link
170− , 'unlink
171− -- Explicit dictionaries
172− , 'sendDict
173− , 'expectDict
174− , 'newChanDict
175− -- Serialization dictionaries
176− , 'sdictComp
177− -- Specialized processes
178− , 'unClosure
179− , 'unDynamic
180− , 'kleisliCompDyn
181− , 'cpFirstAux
182− , 'cpSecondAux
183− ]
184−
185−--------------------------------------------------------------------------------
186−-- Some derived static functions --
187−--------------------------------------------------------------------------------
188−
189−staticUndynamic :: Typeable a => Static (Process Dynamic -> Process a)
190−staticUndynamic =
191− $(mkStatic 'unDynamic) `staticApply` staticDuplicate (staticTypeOf (undefined :: a))
192−
193−staticKleisliCompDyn :: Static ((Process Dynamic, Process Dynamic) -> Process Dynamic)
194−staticKleisliCompDyn = $(mkStatic 'kleisliCompDyn) `staticApply` staticUnit
195−
196−--------------------------------------------------------------------------------
197−-- Definition of CP and the generalized arrow combinators --
198−--------------------------------------------------------------------------------
199−
200−-- | 'CP a b' represents the closure of a process parameterized by 'a' and
201−-- returning 'b'. 'CP a b' forms a (restricted) generalized arrow
202−-- (<http://www.cs.berkeley.edu/~megacz/garrows/>)
203−type CP a b = Closure (a -> Process b)
204−
205−-- | 'CP' introduction form
206−cpIntro :: forall a b. (Typeable a, Typeable b)
207− => Closure (Process b) -> Closure (a -> Process b)
208−cpIntro (Closure static env) = Closure decoder env
209− where
210− decoder :: Static (ByteString -> a -> Process b)
211− decoder = staticConst `staticCompose` static
212−
213−-- | 'CP' elimination form
214−cpElim :: forall a. Typeable a => CP () a -> Closure (Process a)
215−cpElim (Closure static env) = Closure decoder env
216− where
217− decoder :: Static (ByteString -> Process a)
218− decoder = staticFlip static `staticApply` staticUnit
219−
220−-- | Identity ('Closure' version of 'return')
221−cpId :: Typeable a => CP a a
222−cpId = staticClosure $(mkStatic 'returnProcess)
223−
224−-- | Left-to-right composition ('Closure' version of '>=>')
225−cpComp :: forall a b c. (Typeable a, Typeable b, Typeable c)
226− => CP a b -> CP b c -> CP a c
227−cpComp (Closure fstatic fenv) (Closure gstatic genv) =
228− Closure decoder (encode (fenv, genv))
229− where
230− decoder :: Static (ByteString -> a -> Process c)
231− decoder = $(mkStatic 'parJoinProcess)
232− `staticCompose`
233− staticUndynamic
234− `staticCompose`
235− staticKleisliCompDyn
236− `staticCompose`
237− (staticUnclosure fstatic `staticSplit` staticUnclosure gstatic)
238− `staticCompose`
239− staticDecode $(mkStatic 'sdictComp)
240−
241−-- | First
242−cpFirst :: forall a b c. (Typeable a, Typeable b, Typeable c)
243− => CP a b -> CP (a, c) (b, c)
244−cpFirst (Closure static env) = Closure decoder env
245− where
246− decoder :: Static (ByteString -> (a, c) -> Process (b, c))
247− decoder = $(mkStatic 'cpFirstAux) `staticCompose` static
248−
249−-- | Second
250−cpSecond :: forall a b c. (Typeable a, Typeable b, Typeable c)
251− => CP a b -> CP (c, a) (c, b)
252−cpSecond (Closure static env) = Closure decoder env
253− where
254− decoder :: Static (ByteString -> (c, a) -> Process (c, b))
255− decoder = $(mkStatic 'cpSecondAux) `staticCompose` static
256−
257−-- | Split (Like 'Control.Arrow.***')
258−cpSplit :: (Typeable a, Typeable b, Typeable c, Typeable d)
259− => CP a c -> CP b d -> CP (a, b) (c, d)
260−cpSplit f g = cpFirst f `cpComp` cpSecond g
261−
262−-- | Left cancellation
263−cpCancelL :: Typeable a => CP ((), a) a
264−-- Closure (((), a) -> Process a)
265−cpCancelL = staticClosure ($(mkStatic 'returnProcess) `staticCompose` staticSnd)
266−
267−-- | Right cancellation
268−cpCancelR :: Typeable a => CP (a, ()) a
269−cpCancelR = staticClosure ($(mkStatic 'returnProcess) `staticCompose` staticFst)
270−
271−--------------------------------------------------------------------------------
272−-- Closure versions of CH primitives --
273−--------------------------------------------------------------------------------
274−
275−-- | Closure version of 'link'
276−cpLink :: ProcessId -> Closure (Process ())
277−cpLink = $(mkClosure 'link)
278−
279−-- | Closure version of 'unlink'
280−cpUnlink :: ProcessId -> Closure (Process ())
281−cpUnlink = $(mkClosure 'unlink)
282−
283−-- | Closure version of 'send'
284−cpSend :: forall a. Typeable a
285− => Static (SerializableDict a) -> ProcessId -> Closure (a -> Process ())
286−cpSend dict pid = Closure decoder (encode pid)
287− where
288− decoder :: Static (ByteString -> a -> Process ())
289− decoder = ($(mkStatic 'sendDict) `staticApply` dict)
290− `staticCompose`
291− staticDecode sdictProcessId
292−
293−-- | Closure version of 'expect'
294−cpExpect :: Typeable a => Static (SerializableDict a) -> Closure (Process a)
295−cpExpect dict = staticClosure ($(mkStatic 'expectDict) `staticApply` dict)
296−
297−-- | Closure version of 'newChan'
298−cpNewChan :: Typeable a
299− => Static (SerializableDict a)
300− -> Closure (Process (SendPort a, ReceivePort a))
301−cpNewChan dict = staticClosure ($(mkStatic 'newChanDict) `staticApply` dict)
302−
303−--------------------------------------------------------------------------------
304−-- (Closure . Process) as a not-quite-monad --
305−--------------------------------------------------------------------------------
306−
307−-- | Not-quite-monadic 'return'
308−cpReturn :: forall a. Serializable a
309− => Static (SerializableDict a) -> a -> Closure (Process a)
310−cpReturn dict x = Closure decoder (encode x)
311− where
312− decoder :: Static (ByteString -> Process a)
313− decoder = $(mkStatic 'returnProcess)
314− `staticCompose`
315− staticDecode dict
316−
317−
318−staticUnclosure :: Typeable a
319− => Static a -> Static (ByteString -> Process Dynamic)
320−staticUnclosure s =
321− $(mkStatic 'unClosure) `staticApply` staticDuplicate s
322−
323−-- | Not-quite-monadic bind ('>>=')
324−cpBind :: forall a b. (Typeable a, Typeable b)
325− => Closure (Process a) -> Closure (a -> Process b) -> Closure (Process b)
326−cpBind x f = cpElim (cpIntro x `cpComp` f)
327−
328−-- | Monadic sequencing ('>>')
329−cpSeq :: Closure (Process ()) -> Closure (Process ()) -> Closure (Process ())
330−cpSeq p q = p `cpBind` cpIntro q
distributed-process/src/Control/Distributed/Process/Internal/Closure/MkClosure.hs+6−1
@@ -3,15 +3,20 @@ module Control.Distributed.Process.Internal.Closure.MkClosure (mkClosure) where
3
3
4import Data.Binary (encode)
4import Data.Binary (encode)
5import Language.Haskell.TH (Q, Exp, Name)
5import Language.Haskell.TH (Q, Exp, Name)
6−import Control.Distributed.Process.Internal.Types (Closure(Closure))
7import Control.Distributed.Process.Internal.Closure.TH
6import Control.Distributed.Process.Internal.Closure.TH
8 ( mkStatic
7 ( mkStatic
9 , functionSDict
8 , functionSDict
10 )
9 )
10+import Control.Distributed.Static (Closure(Closure), staticCompose)
11+import Control.Distributed.Process.Internal.Closure.BuiltIn (staticDecode)
12+
13+{-
14+-- import Control.Distributed.Process.Internal.Types (Closure(Closure))
11import Control.Distributed.Process.Internal.Closure.Static
15import Control.Distributed.Process.Internal.Closure.Static
12 ( staticCompose
16 ( staticCompose
13 , staticDecode
17 , staticDecode
14 )
18 )
19+-}
15
20
16-- | Create a closure
21-- | Create a closure
17--
22--
distributed-process/src/Control/Distributed/Process/Internal/Closure/Resolution.hsdeleted−34
@@ -1,34 +0,0 @@
1−{-# LANGUAGE MagicHash #-}
2−module Control.Distributed.Process.Internal.Closure.Resolution (resolveClosure) where
3−
4−import Data.Accessor ((^.))
5−import Data.ByteString.Lazy (ByteString)
6−import Control.Distributed.Process.Internal.Types
7− ( RemoteTable
8− , remoteTableLabel
9− , Static(Static)
10− , StaticLabel(..)
11− )
12−import Control.Distributed.Process.Internal.Dynamic
13− ( Dynamic(Dynamic)
14− , toDyn
15− , dynApply
16− , unsafeCoerce#
17− )
18−import Control.Distributed.Process.Internal.TypeRep () -- Binary instances
19−
20−resolveStatic :: RemoteTable -> Static a -> Maybe Dynamic
21−resolveStatic rtable (Static (StaticLabel string typ)) = do
22− Dynamic _ val <- rtable ^. remoteTableLabel string
23− return (Dynamic typ val)
24−resolveStatic rtable (Static (StaticApply static1 static2)) = do
25− f <- resolveStatic rtable (Static static1)
26− x <- resolveStatic rtable (Static static2)
27− f `dynApply` x
28−resolveStatic _rtable (Static (StaticDuplicate static typ)) =
29− return $ Dynamic typ (unsafeCoerce# (Static static))
30−
31−resolveClosure :: RemoteTable -> Static a -> ByteString -> Maybe Dynamic
32−resolveClosure rtable static env = do
33− decoder <- resolveStatic rtable static
34− decoder `dynApply` toDyn env
distributed-process/src/Control/Distributed/Process/Internal/Closure/Static.hsdeleted−190
@@ -1,190 +0,0 @@
1−-- | Combinators on static values
2−{-# LANGUAGE MagicHash #-}
3−module Control.Distributed.Process.Internal.Closure.Static
4− ( -- * Static functionals
5− staticConst
6− , staticFlip
7− , staticFst
8− , staticSnd
9− , staticCompose
10− , staticFirst
11− , staticSecond
12− , staticSplit
13− -- * Static constants
14− , staticUnit
15− -- * Creating closures
16− , staticDecode
17− , staticClosure
18− , toClosure
19− -- * Serialization dictionaries (and their static versions)
20− , sdictUnit
21− , sdictProcessId
22− , sdictSendPort
23− -- * Runtime support
24− , __remoteTable
25− ) where
26−
27−import Data.Binary (encode, decode)
28−import Data.ByteString.Lazy (ByteString, empty)
29−import Data.Typeable (Typeable)
30−import Control.Distributed.Process.Serializable (Serializable)
31−import Control.Distributed.Process.Internal.Types
32− ( Closure(Closure)
33− , SerializableDict(SerializableDict)
34− , Static
35− , staticApply
36− , ProcessId
37− , SendPort
38− )
39−import Control.Distributed.Process.Internal.Closure.TH (remotable, mkStatic)
40−import qualified Control.Arrow as Arrow (first, second, (***))
41−
42−--------------------------------------------------------------------------------
43−-- Setup: A number of functions that we will pass to 'remotable' --
44−--------------------------------------------------------------------------------
45−
46−---- Functionals ---------------------------------------------------------------
47−
48−compose :: (b -> c) -> (a -> b) -> a -> c
49−compose = (.)
50−
51−first :: (a -> b) -> (a, c) -> (b, c)
52−first = Arrow.first
53−
54−second :: (a -> b) -> (c, a) -> (c, b)
55−second = Arrow.second
56−
57−split :: (a -> b) -> (a' -> b') -> (a, a') -> (b, b')
58−split = (Arrow.***)
59−
60−---- Constants -----------------------------------------------------------------
61−
62−unit :: ()
63−unit = ()
64−
65−---- Variations on standard or CH functions with an explicit dictionary arg ----
66−
67−decodeDict :: SerializableDict a -> ByteString -> a
68−decodeDict SerializableDict = decode
69−
70−---- Serialization dictionaries ------------------------------------------------
71−
72−sdictUnit_ :: SerializableDict ()
73−sdictUnit_ = SerializableDict
74−
75−sdictProcessId_ :: SerializableDict ProcessId
76−sdictProcessId_ = SerializableDict
77−
78−sdictSendPort_ :: SerializableDict a -> SerializableDict (SendPort a)
79−sdictSendPort_ SerializableDict = SerializableDict
80−
81−---- Finally, the call to remotable --------------------------------------------
82−
83−remotable [ -- Functionals (predefined)
84− 'const
85− , 'flip
86− , 'fst
87− , 'snd
88− -- Functionals (defined above)
89− , 'compose
90− , 'first
91− , 'second
92− , 'split
93− -- Constants
94− , 'unit
95− -- Explicit dictionaries
96− , 'decodeDict
97− -- Serialization dictionaries
98− , 'sdictUnit_
99− , 'sdictProcessId_
100− , 'sdictSendPort_
101− ]
102−
103−--------------------------------------------------------------------------------
104−-- Static versions of the functionals --
105−-- (We give these explicit names because they are useful outside this module) --
106−--------------------------------------------------------------------------------
107−
108−-- | Static version of 'const'
109−staticConst :: (Typeable a, Typeable b) => Static (a -> b -> a)
110−staticConst = $(mkStatic 'const)
111−
112−-- | Static version of 'flip'
113−staticFlip :: (Typeable a, Typeable b, Typeable c)
114− => Static (a -> b -> c) -> Static (b -> a -> c)
115−staticFlip f = $(mkStatic 'flip) `staticApply` f
116−
117−-- | Static version of 'fst'
118−staticFst :: (Typeable a, Typeable b)
119− => Static ((a, b) -> a)
120−staticFst = $(mkStatic 'fst)
121−
122−-- | Static version of 'snd'
123−staticSnd :: (Typeable a, Typeable b)
124− => Static ((a, b) -> b)
125−staticSnd = $(mkStatic 'snd)
126−
127−-- | Static version of ('Prelude..')
128−staticCompose :: (Typeable a, Typeable b, Typeable c)
129− => Static (b -> c) -> Static (a -> b) -> Static (a -> c)
130−staticCompose f x = $(mkStatic 'compose) `staticApply` f `staticApply` x
131−
132−-- | Static version of 'Control.Arrow.first'
133−staticFirst :: (Typeable a, Typeable b, Typeable c)
134− => Static ((a -> b) -> (a, c) -> (b, c))
135−staticFirst = $(mkStatic 'first)
136−
137−-- | Static version of 'Control.Arrow.second'
138−staticSecond :: (Typeable a, Typeable b, Typeable c)
139− => Static ((a -> b) -> (c, a) -> (c, b))
140−staticSecond = $(mkStatic 'second)
141−
142−-- | Static version of ('Control.Arrow.***')
143−staticSplit :: (Typeable a, Typeable b, Typeable c, Typeable d)
144− => Static (a -> c) -> Static (b -> d) -> Static ((a, b) -> (c, d))
145−staticSplit f g = $(mkStatic 'split) `staticApply` f `staticApply` g
146−
147−--------------------------------------------------------------------------------
148−-- Constants --
149−--------------------------------------------------------------------------------
150−
151−-- | Static version of '()'
152−staticUnit :: Static ()
153−staticUnit = $(mkStatic 'unit)
154−
155−--------------------------------------------------------------------------------
156−-- Dictionaries --
157−--------------------------------------------------------------------------------
158−
159−-- | Serialization dictionary for '()'
160−sdictUnit :: Static (SerializableDict ())
161−sdictUnit = $(mkStatic 'sdictUnit_)
162−
163−-- | Serialization dictionary for 'ProcessId'
164−sdictProcessId :: Static (SerializableDict ProcessId)
165−sdictProcessId = $(mkStatic 'sdictProcessId_)
166−
167−-- | Serialization dictionary for 'SendPort'
168−sdictSendPort :: Typeable a
169− => Static (SerializableDict a) -> Static (SerializableDict (SendPort a))
170−sdictSendPort = staticApply $(mkStatic 'sdictSendPort_)
171−
172−--------------------------------------------------------------------------------
173−-- Creating closures --
174−--------------------------------------------------------------------------------
175−
176−-- | Static decoder, given a static serialization dictionary.
177−--
178−-- See module documentation of "Control.Distributed.Process.Closure" for an
179−-- example.
180−staticDecode :: Typeable a => Static (SerializableDict a) -> Static (ByteString -> a)
181−staticDecode dict = $(mkStatic 'decodeDict) `staticApply` dict
182−
183−-- | Convert a static value into a closure.
184−staticClosure :: forall a. Typeable a => Static a -> Closure a
185−staticClosure static = Closure (staticConst `staticApply` static) empty
186−
187−-- | Convert a serializable value into a closure.
188−toClosure :: forall a. Serializable a
189− => Static (SerializableDict a) -> a -> Closure a
190−toClosure dict x = Closure (staticDecode dict) (encode x)
distributed-process/src/Control/Distributed/Process/Internal/Closure/TH.hs+22−20
@@ -1,7 +1,6 @@
1-- | Template Haskell support
1-- | Template Haskell support
2--
2--
3-- (In a separate file for convenience)
3-- (In a separate file for convenience)
4−{-# LANGUAGE MagicHash #-}
5module Control.Distributed.Process.Internal.Closure.TH
4module Control.Distributed.Process.Internal.Closure.TH
6 ( -- * User-level API
5 ( -- * User-level API
7 remotable
6 remotable
@@ -11,8 +10,6 @@ module Control.Distributed.Process.Internal.Closure.TH
11 ) where
10 ) where
12
11
13import Prelude hiding (lookup)
12import Prelude hiding (lookup)
14−import Data.Accessor ((^=))
15−import Data.Typeable (typeOf)
16import Control.Applicative ((<$>))
13import Control.Applicative ((<$>))
17import Language.Haskell.TH
14import Language.Haskell.TH
18 ( -- Q monad and operations
15 ( -- Q monad and operations
@@ -42,6 +39,21 @@ import Language.Haskell.TH
42 , funD
39 , funD
43 , sigD
40 , sigD
44 )
41 )
42+
43+import Control.Distributed.Process.Internal.Types (Process)
44+import Control.Distributed.Process.Serializable
45+ ( SerializableDict(SerializableDict)
46+ )
47+import Control.Distributed.Static
48+ ( RemoteTable
49+ , toDyn
50+ , unsafeToDyn
51+ , registerStatic
52+ , Static
53+ , staticLabel
54+ )
55+
56+{-
45import Control.Distributed.Process.Internal.Types
57import Control.Distributed.Process.Internal.Types
46 ( RemoteTable
58 ( RemoteTable
47 , Static(Static)
59 , Static(Static)
@@ -50,11 +62,15 @@ import Control.Distributed.Process.Internal.Types
50 , SerializableDict(SerializableDict)
62 , SerializableDict(SerializableDict)
51 , Process
63 , Process
52 )
64 )
65+-}
66+
67+{-
53import Control.Distributed.Process.Internal.Dynamic
68import Control.Distributed.Process.Internal.Dynamic
54 ( Dynamic(..)
69 ( Dynamic(..)
55 , unsafeCoerce#
70 , unsafeCoerce#
56 , toDyn
71 , toDyn
57 )
72 )
73+-}
58
74
59--------------------------------------------------------------------------------
75--------------------------------------------------------------------------------
60-- User-level API --
76-- User-level API --
@@ -141,9 +157,7 @@ generateDefs n = do
141 static <- generateStatic origName typVars typ
157 static <- generateStatic origName typVars typ
142 let dyn = case typVars of
158 let dyn = case typVars of
143 [] -> [| toDyn $(varE origName) |]
159 [] -> [| toDyn $(varE origName) |]
144− _ -> [| Dynamic (error "Polymorphic value")
145− (unsafeCoerce# $(varE origName))
160+ _ -> [| unsafeToDyn $(varE origName) |]
146− |]
147 return ( static
161 return ( static
148 , [ [| registerStatic $(stringE (show origName)) $dyn |] ]
162 , [ [| registerStatic $(stringE (show origName)) $dyn |] ]
149 )
163 )
@@ -156,10 +170,6 @@ generateDefs n = do
156 , [ [| registerStatic $(stringE (show dictName)) $dyn |] ]
170 , [ [| registerStatic $(stringE (show dictName)) $dyn |] ]
157 )
171 )
158
172
159−
160−registerStatic :: String -> Dynamic -> RemoteTable -> RemoteTable
161−registerStatic label dyn = remoteTableLabel label ^= Just dyn
162−
163-- | Generate a static value
173-- | Generate a static value
164generateStatic :: Name -> [TyVarBndr] -> Type -> Q [Dec]
174generateStatic :: Name -> [TyVarBndr] -> Type -> Q [Dec]
165generateStatic n xs typ = do
175generateStatic n xs typ = do
@@ -170,11 +180,7 @@ generateStatic n xs typ = do
170 (map typeable xs)
180 (map typeable xs)
171 (staticTyp `AppT` typ)
181 (staticTyp `AppT` typ)
172 )
182 )
173− , sfnD (staticName n)
183+ , sfnD (staticName n) [| staticLabel $(stringE (show n)) |]
174− [| Static $ StaticLabel
175− $(stringE (show n))
176− (typeOf (undefined :: $(return typ)))
177− |]
178 ]
184 ]
179 where
185 where
180 typeable :: TyVarBndr -> Pred
186 typeable :: TyVarBndr -> Pred
@@ -186,11 +192,7 @@ generateDict :: Name -> Type -> Q [Dec]
186generateDict n typ = do
192generateDict n typ = do
187 sequence
193 sequence
188 [ sigD n $ [t| Static (SerializableDict $(return typ)) |]
194 [ sigD n $ [t| Static (SerializableDict $(return typ)) |]
189− , sfnD n
190− [| Static $ StaticLabel
191− $(stringE (show n))
195+ , sfnD n [| staticLabel $(stringE (show n)) |]
192− (typeOf (undefined :: SerializableDict $(return typ)))
193− |]
194 ]
196 ]
195
197
196staticName :: Name -> Name
198staticName :: Name -> Name
distributed-process/src/Control/Distributed/Process/Internal/Dynamic.hsdeleted−112
@@ -1,112 +0,0 @@
1−-- | Reimplementation of Dynamic that supports dynBind
2−--
3−-- We don't have access to the internal representation of Dynamic, otherwise
4−-- we would not have to redefine it completely. Note that we use this only
5−-- internally, so the incompatibility with "our" Dynamic from the standard
6−-- Dynamic is not important.
7−{-# LANGUAGE MagicHash #-}
8−module Control.Distributed.Process.Internal.Dynamic
9− ( Dynamic(..)
10− , toDyn
11− , fromDyn
12− , fromDynamic
13− , dynTypeRep
14− , dynApply
15− , dynApp
16− , dynBind
17− , dynBind'
18− , dynKleisli
19− , GHC.unsafeCoerce#
20− ) where
21−
22−import Data.Typeable
23− ( Typeable
24− , TypeRep
25− , typeOf
26− , funResultTy
27− , TyCon
28− , splitTyConApp
29− , mkFunTy
30− )
31−import Data.Typeable.Internal (funTc)
32−import qualified GHC.Prim as GHC (Any, unsafeCoerce#)
33−import Data.Maybe (fromMaybe)
34−
35−data Dynamic = Dynamic TypeRep GHC.Any
36− deriving Typeable
37−
38−toDyn :: Typeable a => a -> Dynamic
39−toDyn x = Dynamic (typeOf x) (GHC.unsafeCoerce# x)
40−
41−fromDyn :: Typeable a => Dynamic -> a -> a
42−fromDyn (Dynamic rep val) a =
43− if rep == typeOf a
44− then GHC.unsafeCoerce# val
45− else a
46−
47−fromDynamic :: forall a. Typeable a => Dynamic -> Maybe a
48−fromDynamic (Dynamic rep val) =
49− if rep == typeOf (undefined :: a)
50− then Just (GHC.unsafeCoerce# val)
51− else Nothing
52−
53−dynTypeRep :: Dynamic -> TypeRep
54−dynTypeRep (Dynamic t _) = t
55−
56−instance Show Dynamic where
57− show = show . dynTypeRep
58−
59−dynApply :: Dynamic -> Dynamic -> Maybe Dynamic
60−dynApply (Dynamic t1 f) (Dynamic t2 x) =
61− case funResultTy t1 t2 of
62− Just t3 -> Just (Dynamic t3 (GHC.unsafeCoerce# f x))
63− Nothing -> Nothing
64−
65−dynApp :: Dynamic -> Dynamic -> Dynamic
66−dynApp f x = fromMaybe (error typeError) (dynApply f x)
67− where
68− typeError = "Type error in dynamic application.\n"
69− ++ "Can't apply function " ++ show f
70− ++ " to argument " ++ show x
71−
72−dynBind :: TyCon -> (forall a b. m a -> (a -> m b) -> m b) -> Dynamic -> Dynamic -> Maybe Dynamic
73−dynBind m bind (Dynamic t1 x) (Dynamic t2 f) =
74− case splitTyConApp t1 of
75− (m', [a]) | m' == m ->
76− case funResultTy t2 a of
77− Just mb -> Just (Dynamic mb (GHC.unsafeCoerce# bind x f))
78− _ -> Nothing
79− _ -> Nothing
80−
81−dynBind' :: TyCon -> (forall a b. m a -> (a -> m b) -> m b) -> Dynamic -> Dynamic -> Dynamic
82−dynBind' m bind x f = fromMaybe (error typeError) (dynBind m bind x f)
83− where
84− typeError = "Type error in dynamic bind.\nCan't bind " ++ show x ++ " to " ++ show f
85−
86−
87−
88−
89−-- | Dynamically typed Kleisli composition
90−dynKleisli :: TyCon
91− -> (forall a b c. (a -> m b) -> (b -> m c) -> a -> m c)
92− -> Dynamic
93− -> Dynamic
94− -> Maybe Dynamic
95−dynKleisli m comp (Dynamic tf f) (Dynamic tg g) =
96− case splitTyConApp tf of
97− (arr1, [a, mb]) | arr1 == funTc ->
98− case splitTyConApp tg of
99− (arr2, [b, mc]) | arr2 == funTc ->
100− case splitTyConApp mb of
101− (m', [b']) | m' == m && b' == b ->
102− case splitTyConApp mc of
103− (m'', [_c]) | m'' == m ->
104− Just (Dynamic (mkFunTy a mc) (GHC.unsafeCoerce# comp f g))
105− _ ->
106− Nothing
107− _ ->
108− Nothing
109− _ ->
110− Nothing
111− _ ->
112− Nothing
distributed-process/src/Control/Distributed/Process/Internal/Primitives.hs+9−4
@@ -90,13 +90,18 @@ import Control.Concurrent.STM
90import Control.Distributed.Process.Internal.CQueue (dequeue, BlockSpec(..))
90import Control.Distributed.Process.Internal.CQueue (dequeue, BlockSpec(..))
91import Control.Distributed.Process.Serializable (Serializable, fingerprint)
91import Control.Distributed.Process.Serializable (Serializable, fingerprint)
92import Data.Accessor ((^.), (^:), (^=))
92import Data.Accessor ((^.), (^:), (^=))
93+import Control.Distributed.Static
94+ ( Closure(Closure)
95+ , resolveClosure
96+ , fromDyn
97+ , dynTypeRep
98+ )
93import Control.Distributed.Process.Internal.Types
99import Control.Distributed.Process.Internal.Types
94 ( NodeId(..)
100 ( NodeId(..)
95 , ProcessId(..)
101 , ProcessId(..)
96 , LocalNode(..)
102 , LocalNode(..)
97 , LocalProcess(..)
103 , LocalProcess(..)
98 , Process(..)
104 , Process(..)
99− , Closure(..)
100 , Message(..)
105 , Message(..)
101 , MonitorRef(..)
106 , MonitorRef(..)
102 , SpawnRef(..)
107 , SpawnRef(..)
@@ -104,7 +109,6 @@ import Control.Distributed.Process.Internal.Types
104 , ProcessSignal(..)
109 , ProcessSignal(..)
105 , monitorCounter
110 , monitorCounter
106 , spawnCounter
111 , spawnCounter
107− , Closure(..)
108 , SendPort(..)
112 , SendPort(..)
109 , ReceivePort(..)
113 , ReceivePort(..)
110 , channelCounter
114 , channelCounter
@@ -121,8 +125,9 @@ import Control.Distributed.Process.Internal.Types
121 , runLocalProcess
125 , runLocalProcess
122 )
126 )
123import Control.Distributed.Process.Internal.Node (sendMessage, sendBinary)
127import Control.Distributed.Process.Internal.Node (sendMessage, sendBinary)
128+
124−import Control.Distributed.Process.Internal.Closure.Resolution (resolveClosure)
129+-- import Control.Distributed.Process.Internal.Closure.Resolution (resolveClosure)
125−import Control.Distributed.Process.Internal.Dynamic (fromDyn, dynTypeRep)
130+-- import Control.Distributed.Process.Internal.Dynamic (fromDyn, dynTypeRep)
126
131
127--------------------------------------------------------------------------------
132--------------------------------------------------------------------------------
128-- Basic messaging --
133-- Basic messaging --
distributed-process/src/Control/Distributed/Process/Internal/Types.hs+6−107
@@ -3,7 +3,6 @@
3-- We collect all types used internally in a single module because
3-- We collect all types used internally in a single module because
4-- many of these data types are mutually recursive and cannot be split across
4-- many of these data types are mutually recursive and cannot be split across
5-- modules.
5-- modules.
6−{-# LANGUAGE MagicHash #-}
7module Control.Distributed.Process.Internal.Types
6module Control.Distributed.Process.Internal.Types
8 ( -- * Node and process identifiers
7 ( -- * Node and process identifiers
9 NodeId(..)
8 NodeId(..)
@@ -24,16 +23,6 @@ module Control.Distributed.Process.Internal.Types
24 , TypedChannel(..)
23 , TypedChannel(..)
25 , SendPort(..)
24 , SendPort(..)
26 , ReceivePort(..)
25 , ReceivePort(..)
27− -- * Closures
28− , StaticLabel(..)
29− , Static(..)
30− , staticApply
31− , staticDuplicate
32− , staticTypeOf
33− , typeOfStaticLabel
34− , Closure(..)
35− , RemoteTable(..)
36− , SerializableDict(..)
37 -- * Messages
26 -- * Messages
38 , Message(..)
27 , Message(..)
39 , createMessage
28 , createMessage
@@ -70,15 +59,12 @@ module Control.Distributed.Process.Internal.Types
70 , channelCounter
59 , channelCounter
71 , typedChannels
60 , typedChannels
72 , typedChannelWithId
61 , typedChannelWithId
73− , remoteTableLabels
74− , remoteTableLabel
75 ) where
62 ) where
76
63
77import Data.Map (Map)
64import Data.Map (Map)
78import Data.Int (Int32)
65import Data.Int (Int32)
79−import Data.Maybe (fromJust)
80−import Data.Typeable (Typeable, TypeRep, typeOf, funResultTy)
66+import Data.Typeable (Typeable)
81−import Data.Binary (Binary(put, get), putWord8, getWord8, encode, Put, Get)
67+import Data.Binary (Binary(put, get), putWord8, getWord8, encode)
82import qualified Data.ByteString as BSS (ByteString, concat)
68import qualified Data.ByteString as BSS (ByteString, concat)
83import qualified Data.ByteString.Lazy as BSL
69import qualified Data.ByteString.Lazy as BSL
84 ( ByteString
70 ( ByteString
@@ -108,8 +94,10 @@ import Control.Distributed.Process.Serializable
108 , showFingerprint
94 , showFingerprint
109 )
95 )
110import Control.Distributed.Process.Internal.CQueue (CQueue)
96import Control.Distributed.Process.Internal.CQueue (CQueue)
97+import Control.Distributed.Static (RemoteTable, Closure)
98+
111−import Control.Distributed.Process.Internal.Dynamic (Dynamic)
99+-- import Control.Distributed.Process.Internal.Dynamic (Dynamic)
112−import Control.Distributed.Process.Internal.TypeRep (compareTypeRep) -- and Binary instances
100+-- import Control.Distributed.Process.Internal.TypeRep (compareTypeRep) -- and Binary instances
113
101
114--------------------------------------------------------------------------------
102--------------------------------------------------------------------------------
115-- Node and process identifiers --
103-- Node and process identifiers --
@@ -255,62 +243,6 @@ data ReceivePort a =
255 | ReceivePortRR (TVar [ReceivePort a])
243 | ReceivePortRR (TVar [ReceivePort a])
256 deriving Typeable
244 deriving Typeable
257
245
258−--------------------------------------------------------------------------------
259−-- Closures --
260−--------------------------------------------------------------------------------
261−
262−data StaticLabel =
263− StaticLabel String TypeRep
264− | StaticApply StaticLabel StaticLabel
265− | StaticDuplicate StaticLabel TypeRep
266− deriving (Typeable, Show)
267−
268−-- | A static value is top-level bound or the application of two static values.
269−--
270−-- You construct static values using 'Control.Distributed.Process.Closure.mkStatic'
271−-- or 'staticApply'. 'Static' has a serializable instance for all /Typeable/ 'a':
272−--
273−-- > instance Typeable a => Serializable (Static a)
274−--
275−-- The 'Typeable' constraint (not present in the original Cloud Haskell paper)
276−-- makes it possible to do a type check during deserialization.
277−newtype Static a = Static StaticLabel
278− deriving (Typeable, Show)
279−
280−-- | Apply two static values
281−staticApply :: Static (a -> b) -> Static a -> Static b
282−staticApply (Static f) (Static x) = Static (StaticApply f x)
283−
284−-- | Co-monadic 'duplicate' for static values
285−staticDuplicate :: forall a. Typeable a => Static a -> Static (Static a)
286−staticDuplicate (Static x) =
287− Static (StaticDuplicate x (typeOf (undefined :: Static a)))
288−
289−staticTypeOf :: forall a. Typeable a => a -> Static a
290−staticTypeOf _ = Static (StaticLabel "undefined" (typeOf (undefined :: a)))
291−
292−typeOfStaticLabel :: StaticLabel -> TypeRep
293−typeOfStaticLabel (StaticLabel _ typ)
294− = typ
295−typeOfStaticLabel (StaticApply f x)
296− = fromJust $ funResultTy (typeOfStaticLabel f) (typeOfStaticLabel x)
297−typeOfStaticLabel (StaticDuplicate _ typ)
298− = typ
299−
300−-- | A closure is a static value and an encoded environment
301−data Closure a = Closure (Static (BSL.ByteString -> a)) BSL.ByteString
302− deriving (Typeable, Show)
303−
304−-- | Runtime dictionary for 'unstatic' lookups
305−data RemoteTable = RemoteTable {
306− _remoteTableLabels :: Map String Dynamic
307− }
308−
309−-- | Reification of 'Serializable' (see "Control.Distributed.Process.Closure")
310−data SerializableDict a where
311− SerializableDict :: Serializable a => SerializableDict a
312− deriving (Typeable)
313−
314--------------------------------------------------------------------------------
246--------------------------------------------------------------------------------
315-- Messages --
247-- Messages --
316--------------------------------------------------------------------------------
248--------------------------------------------------------------------------------
@@ -526,10 +458,6 @@ instance Binary DiedReason where
526 4 -> return DiedUnknownId
458 4 -> return DiedUnknownId
527 _ -> fail "DiedReason.get: invalid"
459 _ -> fail "DiedReason.get: invalid"
528
460
529−instance Typeable a => Binary (Closure a) where
530− put (Closure static env) = put static >> put env
531− get = Closure <$> get <*> get
532−
533instance Binary DidSpawn where
461instance Binary DidSpawn where
534 put (DidSpawn ref pid) = put ref >> put pid
462 put (DidSpawn ref pid) = put ref >> put pid
535 get = DidSpawn <$> get <*> get
463 get = DidSpawn <$> get <*> get
@@ -550,29 +478,6 @@ instance Binary Identifier where
550 2 -> SendPortIdentifier <$> get
478 2 -> SendPortIdentifier <$> get
551 _ -> fail "Identifier.get: invalid"
479 _ -> fail "Identifier.get: invalid"
552
480
553−-- We don't want StaticLabel to be its own Binary instance
554−putStaticLabel :: StaticLabel -> Put
555−putStaticLabel (StaticLabel string typ) = putWord8 0 >> put string >> put typ
556−putStaticLabel (StaticApply label1 label2) = putWord8 1 >> putStaticLabel label1 >> putStaticLabel label2
557−putStaticLabel (StaticDuplicate label typ) = putWord8 2 >> putStaticLabel label >> put typ
558−
559−getStaticLabel :: Get StaticLabel
560−getStaticLabel = do
561− header <- getWord8
562− case header of
563− 0 -> StaticLabel <$> get <*> get
564− 1 -> StaticApply <$> getStaticLabel <*> getStaticLabel
565− 2 -> StaticDuplicate <$> getStaticLabel <*> get
566− _ -> fail "StaticLabel.get: invalid"
567−
568−instance Typeable a => Binary (Static a) where
569− put (Static label) = putStaticLabel label
570− get = do
571− label <- getStaticLabel
572− if typeOfStaticLabel label `compareTypeRep` typeOf (undefined :: a)
573− then return $ Static label
574− else fail "Static.get: type error"
575−
576instance Binary WhereIsReply where
481instance Binary WhereIsReply where
577 put (WhereIsReply label mPid) = put label >> put mPid
482 put (WhereIsReply label mPid) = put label >> put mPid
578 get = WhereIsReply <$> get <*> get
483 get = WhereIsReply <$> get <*> get
@@ -613,9 +518,3 @@ typedChannels = accessor _typedChannels (\cs st -> st { _typedChannels = cs })
613
518
614typedChannelWithId :: LocalSendPortId -> Accessor LocalProcessState (Maybe TypedChannel)
519typedChannelWithId :: LocalSendPortId -> Accessor LocalProcessState (Maybe TypedChannel)
615typedChannelWithId cid = typedChannels >>> DAC.mapMaybe cid
520typedChannelWithId cid = typedChannels >>> DAC.mapMaybe cid
616−
617−remoteTableLabels :: Accessor RemoteTable (Map String Dynamic)
618−remoteTableLabels = accessor _remoteTableLabels (\ls tbl -> tbl { _remoteTableLabels = ls })
619−
620−remoteTableLabel :: String -> Accessor RemoteTable (Maybe Dynamic)
621−remoteTableLabel label = remoteTableLabels >>> DAC.mapMaybe label
distributed-process/src/Control/Distributed/Process/Node.hs+15−11
@@ -69,9 +69,14 @@ import qualified Network.Transport as NT
69import Data.Accessor (Accessor, accessor, (^.), (^=), (^:))
69import Data.Accessor (Accessor, accessor, (^.), (^=), (^:))
70import qualified Data.Accessor.Container as DAC (mapDefault, mapMaybe)
70import qualified Data.Accessor.Container as DAC (mapDefault, mapMaybe)
71import System.Random (randomIO)
71import System.Random (randomIO)
72−import Control.Distributed.Process.Internal.Types
72+import Control.Distributed.Static
73 ( RemoteTable
73 ( RemoteTable
74+ , Closure(Closure)
75+ , resolveClosure
76+ , fromDynamic
77+ )
78+import Control.Distributed.Process.Internal.Types
74− , NodeId(..)
79+ ( NodeId(..)
75 , LocalProcessId(..)
80 , LocalProcessId(..)
76 , ProcessId(..)
81 , ProcessId(..)
77 , LocalNode(..)
82 , LocalNode(..)
@@ -98,7 +103,6 @@ import Control.Distributed.Process.Internal.Types
98 , DidUnlinkPort(..)
103 , DidUnlinkPort(..)
99 , SpawnRef
104 , SpawnRef
100 , DidSpawn(..)
105 , DidSpawn(..)
101− , Closure(..)
102 , Message
106 , Message
103 , TypedChannel(..)
107 , TypedChannel(..)
104 , Identifier(..)
108 , Identifier(..)
@@ -107,31 +111,31 @@ import Control.Distributed.Process.Internal.Types
107 , typedChannelWithId
111 , typedChannelWithId
108 , WhereIsReply(..)
112 , WhereIsReply(..)
109 , messageToPayload
113 , messageToPayload
110− , RemoteTable(..)
111 , payloadToMessage
114 , payloadToMessage
112 , createMessage
115 , createMessage
113 , runLocalProcess
116 , runLocalProcess
114 )
117 )
115import Control.Distributed.Process.Serializable (Serializable)
118import Control.Distributed.Process.Serializable (Serializable)
116−import Control.Distributed.Process.Internal.Dynamic (fromDynamic)
117−import Control.Distributed.Process.Internal.Closure.Resolution (resolveClosure)
118import Control.Distributed.Process.Internal.Node
119import Control.Distributed.Process.Internal.Node
119 ( sendBinary
120 ( sendBinary
120 , sendMessage
121 , sendMessage
121 , sendPayload
122 , sendPayload
122 )
123 )
123import Control.Distributed.Process.Internal.Primitives (expect, register, finally)
124import Control.Distributed.Process.Internal.Primitives (expect, register, finally)
124−import qualified Control.Distributed.Process.Internal.Closure.Static as Static (__remoteTable)
125+import qualified Control.Distributed.Process.Internal.Closure.BuiltIn as BuiltIn (remoteTable)
126+import qualified Control.Distributed.Static as Static (initRemoteTable)
127+
128+-- import Control.Distributed.Process.Internal.Dynamic (fromDynamic)
129+-- import Control.Distributed.Process.Internal.Closure.Resolution (resolveClosure)
130+-- import qualified Control.Distributed.Process.Internal.Closure.Static as Static (__remoteTable)
125−import qualified Control.Distributed.Process.Internal.Closure.CP as CP (__remoteTable)
131+-- import qualified Control.Distributed.Process.Internal.Closure.CP as CP (__remoteTable)
126
132
127--------------------------------------------------------------------------------
133--------------------------------------------------------------------------------
128-- Initialization --
134-- Initialization --
129--------------------------------------------------------------------------------
135--------------------------------------------------------------------------------
130
136
131initRemoteTable :: RemoteTable
137initRemoteTable :: RemoteTable
132−initRemoteTable = Static.__remoteTable
138+initRemoteTable = BuiltIn.remoteTable Static.initRemoteTable
133− . CP.__remoteTable
134− $ RemoteTable Map.empty
135
139
136-- | Initialize a new local node.
140-- | Initialize a new local node.
137newLocalNode :: NT.Transport -> RemoteTable -> IO LocalNode
141newLocalNode :: NT.Transport -> RemoteTable -> IO LocalNode
distributed-process/src/Control/Distributed/Process/Serializable.hs+6
@@ -6,6 +6,7 @@ module Control.Distributed.Process.Serializable
6 , sizeOfFingerprint
6 , sizeOfFingerprint
7 , Fingerprint
7 , Fingerprint
8 , showFingerprint
8 , showFingerprint
9+ , SerializableDict(SerializableDict)
9 ) where
10 ) where
10
11
11import Data.Binary (Binary)
12import Data.Binary (Binary)
@@ -23,6 +24,11 @@ import qualified Data.ByteString.Internal as BSI ( unsafeCreate
23import Foreign.Storable (pokeByteOff, peekByteOff, sizeOf)
24import Foreign.Storable (pokeByteOff, peekByteOff, sizeOf)
24import Foreign.ForeignPtr (withForeignPtr)
25import Foreign.ForeignPtr (withForeignPtr)
25
26
27+-- | Reification of 'Serializable' (see "Control.Distributed.Process.Closure")
28+data SerializableDict a where
29+ SerializableDict :: Serializable a => SerializableDict a
30+ deriving (Typeable)
31+
26-- | Objects that can be sent across the network
32-- | Objects that can be sent across the network
27class (Binary a, Typeable a) => Serializable a
33class (Binary a, Typeable a) => Serializable a
28instance (Binary a, Typeable a) => Serializable a
34instance (Binary a, Typeable a) => Serializable a
distributed-process/tests/TestClosure.hs+6−6
@@ -12,7 +12,7 @@ import Network.Transport.TCP (createTransport, defaultTCPParameters)
12import Control.Distributed.Process
12import Control.Distributed.Process
13import Control.Distributed.Process.Closure
13import Control.Distributed.Process.Closure
14import Control.Distributed.Process.Node
14import Control.Distributed.Process.Node
15−import Control.Distributed.Process.Internal.Types (Static(Static), StaticLabel(StaticLabel))
15+import Control.Distributed.Static (staticLabel)
16import TestAuxiliary
16import TestAuxiliary
17
17
18sdictInt :: SerializableDict Int
18sdictInt :: SerializableDict Int
@@ -71,13 +71,13 @@ sendPidClosure :: ProcessId -> Closure (Process ())
71sendPidClosure = $(mkClosure 'sendPid)
71sendPidClosure = $(mkClosure 'sendPid)
72
72
73sendFac :: Int -> ProcessId -> Closure (Process ())
73sendFac :: Int -> ProcessId -> Closure (Process ())
74−sendFac n pid = factorialClosure n `cpBind` cpSend $(mkStatic 'sdictInt) pid
74+sendFac n pid = factorialClosure n `bindCP` cpSend $(mkStatic 'sdictInt) pid
75
75
76factorialOf :: Closure (Int -> Process Int)
76factorialOf :: Closure (Int -> Process Int)
77factorialOf = staticClosure $(mkStatic 'factorial)
77factorialOf = staticClosure $(mkStatic 'factorial)
78
78
79factorial' :: Int -> Closure (Process Int)
79factorial' :: Int -> Closure (Process Int)
80−factorial' n = cpReturn $(mkStatic 'sdictInt) n `cpBind` factorialOf
80+factorial' n = returnCP $(mkStatic 'sdictInt) n `bindCP` factorialOf
81
81
82waitClosure :: Int -> Closure (Process ())
82waitClosure :: Int -> Closure (Process ())
83waitClosure = $(mkClosure 'wait)
83waitClosure = $(mkClosure 'wait)
@@ -229,7 +229,7 @@ testSeq transport rtable = do
229 node <- newLocalNode transport rtable
229 node <- newLocalNode transport rtable
230 runProcess node $ do
230 runProcess node $ do
231 us <- getSelfPid
231 us <- getSelfPid
232− join . unClosure $ sendFac 5 us `cpSeq` sendFac 6 us
232+ join . unClosure $ sendFac 5 us `seqCP` sendFac 6 us
233 120 :: Int <- expect
233 120 :: Int <- expect
234 720 :: Int <- expect
234 720 :: Int <- expect
235 return ()
235 return ()
@@ -273,7 +273,7 @@ testSpawnInvalid :: Transport -> RemoteTable -> IO ()
273testSpawnInvalid transport rtable = do
273testSpawnInvalid transport rtable = do
274 node <- newLocalNode transport rtable
274 node <- newLocalNode transport rtable
275 runProcess node $ do
275 runProcess node $ do
276− (pid, ref) <- spawnMonitor (localNodeId node) (Closure (Static (StaticLabel "ThisDoesNotExist" (typeOf ()))) empty)
276+ (pid, ref) <- spawnMonitor (localNodeId node) (Closure (staticLabel "ThisDoesNotExist") empty)
277 ProcessMonitorNotification ref' pid' _reason <- expect
277 ProcessMonitorNotification ref' pid' _reason <- expect
278 -- Depending on the exact interleaving, reason might be NoProc or the exception thrown by the absence of the static closure
278 -- Depending on the exact interleaving, reason might be NoProc or the exception thrown by the absence of the static closure
279 True <- return $ ref' == ref && pid == pid'
279 True <- return $ ref' == ref && pid == pid'
@@ -285,7 +285,7 @@ testClosureExpect transport rtable = do
285 runProcess node $ do
285 runProcess node $ do
286 nodeId <- getSelfNode
286 nodeId <- getSelfNode
287 us <- getSelfPid
287 us <- getSelfPid
288− them <- spawn nodeId $ cpExpect $(mkStatic 'sdictInt) `cpBind` cpSend $(mkStatic 'sdictInt) us
288+ them <- spawn nodeId $ cpExpect $(mkStatic 'sdictInt) `bindCP` cpSend $(mkStatic 'sdictInt) us
289 send them (1234 :: Int)
289 send them (1234 :: Int)
290 (1234 :: Int) <- expect
290 (1234 :: Int) <- expect
291 return ()
291 return ()
distributed-static/LICENSEnew file+30
@@ -0,0 +1,30 @@
1+Copyright (c) 2012, Edsko de Vries
2+
3+All rights reserved.
4+
5+Redistribution and use in source and binary forms, with or without
6+modification, are permitted provided that the following conditions are met:
7+
8+ * Redistributions of source code must retain the above copyright
9+ notice, this list of conditions and the following disclaimer.
10+
11+ * Redistributions in binary form must reproduce the above
12+ copyright notice, this list of conditions and the following
13+ disclaimer in the documentation and/or other materials provided
14+ with the distribution.
15+
16+ * Neither the name of Edsko de Vries nor the names of other
17+ contributors may be used to endorse or promote products derived
18+ from this software without specific prior written permission.
19+
20+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
distributed-static/Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
distributed-static/distributed-static.cabalnew file+29
@@ -0,0 +1,29 @@
1+Name: distributed-static
2+Version: 0.1.0.0
3+Synopsis: Workaround the absence of "static" in ghc
4+-- description:
5+Homepage: http://www.github.com/haskell-distributed/distributed-process
6+License: BSD3
7+License-File: LICENSE
8+Author: Edsko de Vries
9+Maintainer: edsko@well-typed.com
10+Copyright: Well-Typed LLP
11+Category: Control
12+Build-Type: Simple
13+Cabal-Version: >=1.8
14+
15+Library
16+ Exposed-Modules: Control.Distributed.Static,
17+ Control.Distributed.Static.Internal.Dynamic,
18+ Control.Distributed.Static.Internal.TypeRep
19+ Build-Depends: base ==4.5.*,
20+ containers >= 0.4 && < 0.5,
21+ bytestring >= 0.0 && < 0.11,
22+ binary >= 0.5 && < 0.6,
23+ ghc-prim >= 0.2 && < 0.3
24+ HS-Source-Dirs: src
25+ Extensions: DeriveDataTypeable,
26+ ScopedTypeVariables,
27+ RankNTypes,
28+ CPP
29+ GHC-Options: -Wall
distributed-static/src/Control/Distributed/Static.hsnew file+352
@@ -0,0 +1,352 @@
1+-- | /Towards Haskell in the Cloud/ introduces a new typing construct called
2+-- @static@. Unfortunately, ghc does not yet include support for @static@. In
3+-- this module we provide a workaround, which at the same time also extends
4+-- the functionality of @static@ as described in the paper and makes it more
5+-- expressive.
6+--
7+-- The main idea (already discussed in /Towards Haskell in the Cloud/, section
8+-- /Faking It/) is to maintain a runtime mapping from labels (strings) to
9+-- values. A basic static value (introduced using 'staticLabel') then is an
10+-- index into this runtime mapping. It is the responsibility of the client code
11+-- to make sure that the corresponding value in the 'RemoteTable' matches the
12+-- type of the label, although we do runtime type checks where possible. For
13+-- this reason, we only work with 'Typeable' values in this module.
14+module Control.Distributed.Static
15+ ( -- * Introducing static values
16+ Static
17+ , staticLabel
18+ , staticApply
19+ , staticDuplicate
20+ , staticTypeOf
21+ -- * Eliminating static values
22+ , RemoteTable
23+ , initRemoteTable
24+ , registerStatic
25+ , resolveStatic
26+ -- * Closures
27+ , Closure(Closure)
28+ , staticClosure
29+ , resolveClosure
30+ -- * Static values
31+ , idStatic
32+ , composeStatic
33+ , constStatic
34+ , flipStatic
35+ , fstStatic
36+ , sndStatic
37+ , firstStatic
38+ , secondStatic
39+ , splitStatic
40+ , unitStatic
41+ , appStatic
42+ -- * Combinators on static values
43+ , staticCompose
44+ , staticSplit
45+ , staticConst
46+ -- * Combinators on closures
47+ , closureApplyStatic
48+ , closureApply
49+ , closureCompose
50+ , closureSplit
51+ -- * Re-exports
52+ , Dynamic
53+ , toDyn
54+ , unsafeToDyn
55+ , fromDyn
56+ , fromDynamic
57+ , dynTypeRep
58+ ) where
59+
60+import Prelude hiding (id, (.))
61+import Data.Typeable
62+ ( Typeable
63+ , TypeRep
64+ , typeOf
65+ , funResultTy
66+ )
67+import Data.Maybe (fromJust)
68+import Data.Binary
69+ ( Binary(get, put)
70+ , Put
71+ , Get
72+ , putWord8
73+ , getWord8
74+ , encode
75+ , decode
76+ )
77+import Data.ByteString.Lazy (ByteString, empty)
78+import Data.Map (Map)
79+import qualified Data.Map as Map (lookup, empty, insert)
80+import Control.Applicative ((<$>), (<*>))
81+import Control.Category (Category(id, (.)))
82+import qualified Control.Arrow as Arrow (first, second, (***), app)
83+import Control.Distributed.Static.Internal.Dynamic
84+ ( Dynamic
85+ , dynApply
86+ , toDyn
87+ , unsafeToDyn
88+ , fromDyn
89+ , dynTypeRep
90+ , fromDynamic
91+ , unsafeCastDyn
92+ )
93+import Control.Distributed.Static.Internal.TypeRep (compareTypeRep)
94+
95+--------------------------------------------------------------------------------
96+-- Introducing static values --
97+--------------------------------------------------------------------------------
98+
99+data StaticLabel =
100+ StaticLabel String TypeRep
101+ | StaticApply StaticLabel StaticLabel
102+ | StaticDuplicate StaticLabel TypeRep
103+ deriving (Typeable, Show)
104+
105+-- | A static value. Static is opaque; see 'staticLabel', 'staticApply',
106+-- 'staticDuplicate' or 'staticTypeOf'.
107+newtype Static a = Static StaticLabel
108+ deriving (Typeable, Show)
109+
110+instance Typeable a => Binary (Static a) where
111+ put (Static label) = putStaticLabel label
112+ get = do
113+ label <- getStaticLabel
114+ if typeOfStaticLabel label `compareTypeRep` typeOf (undefined :: a)
115+ then return $ Static label
116+ else fail "Static.get: type error"
117+
118+-- We don't want StaticLabel to be its own Binary instance
119+putStaticLabel :: StaticLabel -> Put
120+putStaticLabel (StaticLabel string typ) =
121+ putWord8 0 >> put string >> put typ
122+putStaticLabel (StaticApply label1 label2) =
123+ putWord8 1 >> putStaticLabel label1 >> putStaticLabel label2
124+putStaticLabel (StaticDuplicate label typ) =
125+ putWord8 2 >> putStaticLabel label >> put typ
126+
127+getStaticLabel :: Get StaticLabel
128+getStaticLabel = do
129+ header <- getWord8
130+ case header of
131+ 0 -> StaticLabel <$> get <*> get
132+ 1 -> StaticApply <$> getStaticLabel <*> getStaticLabel
133+ 2 -> StaticDuplicate <$> getStaticLabel <*> get
134+ _ -> fail "StaticLabel.get: invalid"
135+
136+-- | Create a primitive static value.
137+--
138+-- It is the responsibility of the client code to make sure the corresponding
139+-- entry in the 'RemoteTable' has the appropriate type.
140+staticLabel :: forall a. Typeable a => String -> Static a
141+staticLabel label = Static (StaticLabel label (typeOf (undefined :: a)))
142+
143+-- | Apply two static values
144+staticApply :: Static (a -> b) -> Static a -> Static b
145+staticApply (Static f) (Static x) = Static (StaticApply f x)
146+
147+-- | Co-monadic 'duplicate' for static values
148+staticDuplicate :: forall a. Typeable a => Static a -> Static (Static a)
149+staticDuplicate (Static x) =
150+ Static (StaticDuplicate x (typeOf (undefined :: Static a)))
151+
152+-- | @staticTypeOf (x :: a)@ mimicks @static (undefined :: a)@ -- even if
153+-- @x@ is not static, the type of @x@ always is.
154+staticTypeOf :: forall a. Typeable a => a -> Static a
155+staticTypeOf _ = Static (StaticLabel "$undefined" (typeOf (undefined :: a)))
156+
157+typeOfStaticLabel :: StaticLabel -> TypeRep
158+typeOfStaticLabel (StaticLabel _ typ)
159+ = typ
160+typeOfStaticLabel (StaticApply f x)
161+ = fromJust $ funResultTy (typeOfStaticLabel f) (typeOfStaticLabel x)
162+typeOfStaticLabel (StaticDuplicate _ typ)
163+ = typ
164+
165+--------------------------------------------------------------------------------
166+-- Eliminating static values --
167+--------------------------------------------------------------------------------
168+
169+-- | Runtime dictionary for 'unstatic' lookups
170+newtype RemoteTable = RemoteTable (Map String Dynamic)
171+
172+-- | Initial remote table
173+initRemoteTable :: RemoteTable
174+initRemoteTable =
175+ registerStatic "$id" (unsafeToDyn identity)
176+ . registerStatic "$compose" (unsafeToDyn compose)
177+ . registerStatic "$const" (unsafeToDyn const)
178+ . registerStatic "$flip" (unsafeToDyn flip)
179+ . registerStatic "$fst" (unsafeToDyn fst)
180+ . registerStatic "$snd" (unsafeToDyn snd)
181+ . registerStatic "$first" (unsafeToDyn first)
182+ . registerStatic "$second" (unsafeToDyn second)
183+ . registerStatic "$split" (unsafeToDyn split)
184+ . registerStatic "$unit" (toDyn ())
185+ . registerStatic "$app" (unsafeToDyn app)
186+ . registerStatic "$decodeEnvPair" (toDyn decodeEnvPair)
187+ $ RemoteTable Map.empty
188+ where
189+ identity :: a -> a
190+ identity = id
191+
192+ compose :: (b -> c) -> (a -> b) -> a -> c
193+ compose = (.)
194+
195+ first :: (a -> b) -> (a, c) -> (b, c)
196+ first = Arrow.first
197+
198+ second :: (a -> b) -> (c, a) -> (c, b)
199+ second = Arrow.second
200+
201+ split :: (a -> b) -> (a' -> b') -> (a, a') -> (b, b')
202+ split = (Arrow.***)
203+
204+ decodeEnvPair :: ByteString -> (ByteString, ByteString)
205+ decodeEnvPair = decode
206+
207+ app :: (a -> b, a) -> b
208+ app = Arrow.app
209+
210+-- | Register a static label
211+registerStatic :: String -> Dynamic -> RemoteTable -> RemoteTable
212+registerStatic label dyn (RemoteTable rtable)
213+ = RemoteTable (Map.insert label dyn rtable)
214+
215+-- | Resolve a Static value.
216+resolveStatic :: RemoteTable -> Static a -> Maybe Dynamic
217+resolveStatic (RemoteTable rtable) (Static (StaticLabel string typ)) = do
218+ unsafeCastDyn (const typ) <$> Map.lookup string rtable
219+resolveStatic rtable (Static (StaticApply static1 static2)) = do
220+ f <- resolveStatic rtable (Static static1)
221+ x <- resolveStatic rtable (Static static2)
222+ f `dynApply` x
223+resolveStatic _rtable (Static (StaticDuplicate static typ)) =
224+ return . unsafeCastDyn (const typ) $ unsafeToDyn (Static static)
225+
226+--------------------------------------------------------------------------------
227+-- Closures --
228+--------------------------------------------------------------------------------
229+
230+-- | A closure is a static value and an encoded environment
231+data Closure a = Closure (Static (ByteString -> a)) ByteString
232+ deriving (Typeable, Show)
233+
234+instance Typeable a => Binary (Closure a) where
235+ put (Closure static env) = put static >> put env
236+ get = Closure <$> get <*> get
237+
238+-- | Convert a static value into a closure.
239+staticClosure :: forall a. Typeable a => Static a -> Closure a
240+staticClosure static = Closure (staticConst static) empty
241+
242+-- | Resolve a Closure
243+resolveClosure :: RemoteTable -> Static a -> ByteString -> Maybe Dynamic
244+resolveClosure rtable static env = do
245+ decoder <- resolveStatic rtable static
246+ decoder `dynApply` toDyn env
247+
248+--------------------------------------------------------------------------------
249+-- Predefined static values --
250+--------------------------------------------------------------------------------
251+
252+-- | Static version of 'id'
253+idStatic :: (Typeable a)
254+ => Static (a -> a)
255+idStatic = staticLabel "$id"
256+
257+-- | Static version of ('Prelude..')
258+composeStatic :: (Typeable a, Typeable b, Typeable c)
259+ => Static ((b -> c) -> (a -> b) -> a -> c)
260+composeStatic = staticLabel "$compose"
261+
262+-- | Static version of 'const'
263+constStatic :: (Typeable a, Typeable b)
264+ => Static (a -> b -> a)
265+constStatic = staticLabel "$const"
266+
267+-- | Static version of 'flip'
268+flipStatic :: (Typeable a, Typeable b, Typeable c)
269+ => Static ((a -> b -> c) -> b -> a -> c)
270+flipStatic = staticLabel "$flip"
271+
272+-- | Static version of 'fst'
273+fstStatic :: (Typeable a, Typeable b)
274+ => Static ((a, b) -> a)
275+fstStatic = staticLabel "$fst"
276+
277+-- | Static version of 'snd'
278+sndStatic :: (Typeable a, Typeable b)
279+ => Static ((a, b) -> b)
280+sndStatic = staticLabel "$snd"
281+
282+-- | Static version of 'Arrow.first'
283+firstStatic :: (Typeable a, Typeable b, Typeable c)
284+ => Static ((a -> b) -> (a, c) -> (b, c))
285+firstStatic = staticLabel "$first"
286+
287+-- | Static version of 'Arrow.second'
288+secondStatic :: (Typeable a, Typeable b, Typeable c)
289+ => Static ((a -> b) -> (c, a) -> (c, b))
290+secondStatic = staticLabel "$second"
291+
292+-- | Static version of ('Arrow.***')
293+splitStatic :: (Typeable a, Typeable a', Typeable b, Typeable b')
294+ => Static ((a -> b) -> (a' -> b') -> (a, a') -> (b, b'))
295+splitStatic = staticLabel "$split"
296+
297+-- | Static version of @()@
298+unitStatic :: Static ()
299+unitStatic = staticLabel "$unit"
300+
301+-- | Static version of 'Arrow.app'
302+appStatic :: (Typeable a, Typeable b)
303+ => Static ((a -> b, a) -> b)
304+appStatic = staticLabel "$app"
305+
306+--------------------------------------------------------------------------------
307+-- Combinators on static values --
308+--------------------------------------------------------------------------------
309+
310+staticCompose :: (Typeable a, Typeable b, Typeable c)
311+ => Static (b -> c) -> Static (a -> b) -> Static (a -> c)
312+staticCompose g f = composeStatic `staticApply` g `staticApply` f
313+
314+staticSplit :: (Typeable a, Typeable a', Typeable b, Typeable b')
315+ => Static (a -> b) -> Static (a' -> b') -> Static ((a, a') -> (b, b'))
316+staticSplit f g = splitStatic `staticApply` f `staticApply` g
317+
318+staticConst :: (Typeable a, Typeable b)
319+ => Static a -> Static (b -> a)
320+staticConst x = constStatic `staticApply` x
321+
322+--------------------------------------------------------------------------------
323+-- Combinators on Closures --
324+--------------------------------------------------------------------------------
325+
326+closureApplyStatic :: forall a b. (Typeable a, Typeable b)
327+ => Static (a -> b) -> Closure a -> Closure b
328+closureApplyStatic f (Closure decoder env) =
329+ Closure (f `staticCompose` decoder) env
330+
331+decodeEnvPairStatic :: Static (ByteString -> (ByteString, ByteString))
332+decodeEnvPairStatic = staticLabel "$decodeEnvPair"
333+
334+closureApply :: forall a b. (Typeable a, Typeable b)
335+ => Closure (a -> b) -> Closure a -> Closure b
336+closureApply (Closure fdec fenv) (Closure xdec xenv) =
337+ Closure decoder (encode (fenv, xenv))
338+ where
339+ decoder :: Static (ByteString -> b)
340+ decoder = appStatic
341+ `staticCompose`
342+ (fdec `staticSplit` xdec)
343+ `staticCompose`
344+ decodeEnvPairStatic
345+
346+closureCompose :: (Typeable a, Typeable b, Typeable c)
347+ => Closure (b -> c) -> Closure (a -> b) -> Closure (a -> c)
348+closureCompose g f = composeStatic `closureApplyStatic` g `closureApply` f
349+
350+closureSplit :: (Typeable a, Typeable a', Typeable b, Typeable b')
351+ => Closure (a -> b) -> Closure (a' -> b') -> Closure ((a, a') -> (b, b'))
352+closureSplit f g = splitStatic `closureApplyStatic` f `closureApply` g
distributed-static/src/Control/Distributed/Static/Internal/Dynamic.hsnew file+121
@@ -0,0 +1,121 @@
1+module Control.Distributed.Static.Internal.Dynamic
2+ ( -- * The @Dynamic@ type
3+ Dynamic
4+ -- * Converting to and from @Dynamic@
5+ , toDyn
6+ , fromDyn
7+ , fromDynamic
8+ -- * Applying functions of dynamic type
9+ , dynApply
10+ , dynApp
11+ , dynTypeRep
12+ -- * Additions
13+ , unsafeToDyn
14+ , unsafeCastDyn
15+ ) where
16+
17+import Control.Exception (Exception)
18+import qualified GHC.Prim as GHC (Any)
19+import Data.Typeable (Typeable, TypeRep, typeOf, funResultTy)
20+import Unsafe.Coerce (unsafeCoerce)
21+
22+-------------------------------------------------------------
23+--
24+-- The type Dynamic
25+--
26+-------------------------------------------------------------
27+
28+{-|
29+ A value of type 'Dynamic' is an object encapsulated together with its type.
30+
31+ A 'Dynamic' may only represent a monomorphic value; an attempt to
32+ create a value of type 'Dynamic' from a polymorphically-typed
33+ expression will result in an ambiguity error (see 'toDyn').
34+
35+ 'Show'ing a value of type 'Dynamic' returns a pretty-printed representation
36+ of the object\'s type; useful for debugging.
37+-}
38+data Dynamic = Dynamic TypeRep Obj
39+ deriving Typeable
40+
41+instance Show Dynamic where
42+ -- the instance just prints the type representation.
43+ showsPrec _ (Dynamic t _) =
44+ showString "<<" .
45+ showsPrec 0 t .
46+ showString ">>"
47+
48+instance Exception Dynamic
49+
50+-- Use GHC's primitive 'Any' type to hold the dynamically typed value.
51+--
52+-- In GHC's new eval/apply execution model this type must not look
53+-- like a data type. If it did, GHC would use the constructor convention
54+-- when evaluating it, and this will go wrong if the object is really a
55+-- function. Using Any forces GHC to use
56+-- a fallback convention for evaluating it that works for all types.
57+type Obj = GHC.Any
58+
59+-- | Converts an arbitrary value into an object of type 'Dynamic'.
60+--
61+-- The type of the object must be an instance of 'Typeable', which
62+-- ensures that only monomorphically-typed objects may be converted to
63+-- 'Dynamic'. To convert a polymorphic object into 'Dynamic', give it
64+-- a monomorphic type signature. For example:
65+--
66+-- > toDyn (id :: Int -> Int)
67+--
68+toDyn :: Typeable a => a -> Dynamic
69+toDyn v = Dynamic (typeOf v) (unsafeCoerce v)
70+
71+-- | Converts a 'Dynamic' object back into an ordinary Haskell value of
72+-- the correct type. See also 'fromDynamic'.
73+fromDyn :: Typeable a
74+ => Dynamic -- ^ the dynamically-typed object
75+ -> a -- ^ a default value
76+ -> a -- ^ returns: the value of the first argument, if
77+ -- it has the correct type, otherwise the value of
78+ -- the second argument.
79+fromDyn (Dynamic t v) def
80+ | typeOf def == t = unsafeCoerce v
81+ | otherwise = def
82+
83+-- | Converts a 'Dynamic' object back into an ordinary Haskell value of
84+-- the correct type. See also 'fromDyn'.
85+fromDynamic
86+ :: Typeable a
87+ => Dynamic -- ^ the dynamically-typed object
88+ -> Maybe a -- ^ returns: @'Just' a@, if the dynamically-typed
89+ -- object has the correct type (and @a@ is its value),
90+ -- or 'Nothing' otherwise.
91+fromDynamic (Dynamic t v) =
92+ case unsafeCoerce v of
93+ r | t == typeOf r -> Just r
94+ | otherwise -> Nothing
95+
96+-- (f::(a->b)) `dynApply` (x::a) = (f a)::b
97+dynApply :: Dynamic -> Dynamic -> Maybe Dynamic
98+dynApply (Dynamic t1 f) (Dynamic t2 x) =
99+ case funResultTy t1 t2 of
100+ Just t3 -> Just (Dynamic t3 ((unsafeCoerce f) x))
101+ Nothing -> Nothing
102+
103+dynApp :: Dynamic -> Dynamic -> Dynamic
104+dynApp f x = case dynApply f x of
105+ Just r -> r
106+ Nothing -> error ("Type error in dynamic application.\n" ++
107+ "Can't apply function " ++ show f ++
108+ " to argument " ++ show x)
109+
110+dynTypeRep :: Dynamic -> TypeRep
111+dynTypeRep (Dynamic tr _) = tr
112+
113+--------------------------------------------------------------------------------
114+-- Additions --
115+--------------------------------------------------------------------------------
116+
117+unsafeToDyn :: a -> Dynamic
118+unsafeToDyn x = Dynamic (error "No type rep") (unsafeCoerce x)
119+
120+unsafeCastDyn :: (TypeRep -> TypeRep) -> Dynamic -> Dynamic
121+unsafeCastDyn f (Dynamic t x) = Dynamic (f t) x
distributed-process/src/Control/Distributed/Process/Internal/TypeRep.hs → distributed-static/src/Control/Distributed/Static/Internal/TypeRep.hsrenamed+1−1
@@ -1,6 +1,6 @@
1-- | 'Binary' instances for 'TypeRep', and 'TypeRep' equality (bug workaround)
1-- | 'Binary' instances for 'TypeRep', and 'TypeRep' equality (bug workaround)
2{-# OPTIONS_GHC -fno-warn-orphans #-}
2{-# OPTIONS_GHC -fno-warn-orphans #-}
3−module Control.Distributed.Process.Internal.TypeRep (compareTypeRep) where
3+module Control.Distributed.Static.Internal.TypeRep (compareTypeRep) where
4
4
5import Control.Applicative ((<$>), (<*>))
5import Control.Applicative ((<$>), (<*>))
6import Data.Binary (Binary(get, put))
6import Data.Binary (Binary(get, put))