-- | Combinators on static values {-# LANGUAGE MagicHash #-} module Control.Distributed.Process.Internal.Closure.Static ( -- * Static functionals staticConst , staticFlip , staticFst , staticSnd , staticCompose , staticFirst , staticSecond , staticSplit -- * Static constants , staticUnit -- * Creating closures , staticDecode , staticClosure , toClosure -- * Serialization dictionaries (and their static versions) , sdictUnit , sdictProcessId , sdictSendPort -- * Runtime support , __remoteTable ) where import Data.Binary (encode, decode) import Data.ByteString.Lazy (ByteString, empty) import Data.Typeable (Typeable) import Control.Distributed.Process.Serializable (Serializable) import Control.Distributed.Process.Internal.Types ( Closure(Closure) , SerializableDict(SerializableDict) , Static , staticApply , ProcessId , SendPort ) import Control.Distributed.Process.Internal.Closure.TH (remotable, mkStatic) import qualified Control.Arrow as Arrow (first, second, (***)) -------------------------------------------------------------------------------- -- Setup: A number of functions that we will pass to 'remotable' -- -------------------------------------------------------------------------------- ---- Functionals --------------------------------------------------------------- compose :: (b -> c) -> (a -> b) -> a -> c compose = (.) first :: (a -> b) -> (a, c) -> (b, c) first = Arrow.first second :: (a -> b) -> (c, a) -> (c, b) second = Arrow.second split :: (a -> b) -> (a' -> b') -> (a, a') -> (b, b') split = (Arrow.***) ---- Constants ----------------------------------------------------------------- unit :: () unit = () ---- Variations on standard or CH functions with an explicit dictionary arg ---- decodeDict :: SerializableDict a -> ByteString -> a decodeDict SerializableDict = decode ---- Serialization dictionaries ------------------------------------------------ sdictUnit_ :: SerializableDict () sdictUnit_ = SerializableDict sdictProcessId_ :: SerializableDict ProcessId sdictProcessId_ = SerializableDict sdictSendPort_ :: SerializableDict a -> SerializableDict (SendPort a) sdictSendPort_ SerializableDict = SerializableDict ---- Finally, the call to remotable -------------------------------------------- remotable [ -- Functionals (predefined) 'const , 'flip , 'fst , 'snd -- Functionals (defined above) , 'compose , 'first , 'second , 'split -- Constants , 'unit -- Explicit dictionaries , 'decodeDict -- Serialization dictionaries , 'sdictUnit_ , 'sdictProcessId_ , 'sdictSendPort_ ] -------------------------------------------------------------------------------- -- Static versions of the functionals -- -- (We give these explicit names because they are useful outside this module) -- -------------------------------------------------------------------------------- -- | Static version of 'const' staticConst :: (Typeable a, Typeable b) => Static (a -> b -> a) staticConst = $(mkStatic 'const) -- | Static version of 'flip' staticFlip :: (Typeable a, Typeable b, Typeable c) => Static (a -> b -> c) -> Static (b -> a -> c) staticFlip f = $(mkStatic 'flip) `staticApply` f -- | Static version of 'fst' staticFst :: (Typeable a, Typeable b) => Static ((a, b) -> a) staticFst = $(mkStatic 'fst) -- | Static version of 'snd' staticSnd :: (Typeable a, Typeable b) => Static ((a, b) -> b) staticSnd = $(mkStatic 'snd) -- | Static version of ('Prelude..') staticCompose :: (Typeable a, Typeable b, Typeable c) => Static (b -> c) -> Static (a -> b) -> Static (a -> c) staticCompose f x = $(mkStatic 'compose) `staticApply` f `staticApply` x -- | Static version of 'Control.Arrow.first' staticFirst :: (Typeable a, Typeable b, Typeable c) => Static ((a -> b) -> (a, c) -> (b, c)) staticFirst = $(mkStatic 'first) -- | Static version of 'Control.Arrow.second' staticSecond :: (Typeable a, Typeable b, Typeable c) => Static ((a -> b) -> (c, a) -> (c, b)) staticSecond = $(mkStatic 'second) -- | Static version of ('Control.Arrow.***') staticSplit :: (Typeable a, Typeable b, Typeable c, Typeable d) => Static (a -> c) -> Static (b -> d) -> Static ((a, b) -> (c, d)) staticSplit f g = $(mkStatic 'split) `staticApply` f `staticApply` g -------------------------------------------------------------------------------- -- Constants -- -------------------------------------------------------------------------------- -- | Static version of '()' staticUnit :: Static () staticUnit = $(mkStatic 'unit) -------------------------------------------------------------------------------- -- Dictionaries -- -------------------------------------------------------------------------------- -- | Serialization dictionary for '()' sdictUnit :: Static (SerializableDict ()) sdictUnit = $(mkStatic 'sdictUnit_) -- | Serialization dictionary for 'ProcessId' sdictProcessId :: Static (SerializableDict ProcessId) sdictProcessId = $(mkStatic 'sdictProcessId_) -- | Serialization dictionary for 'SendPort' sdictSendPort :: Typeable a => Static (SerializableDict a) -> Static (SerializableDict (SendPort a)) sdictSendPort = staticApply $(mkStatic 'sdictSendPort_) -------------------------------------------------------------------------------- -- Creating closures -- -------------------------------------------------------------------------------- -- | Static decoder, given a static serialization dictionary. -- -- See module documentation of "Control.Distributed.Process.Closure" for an -- example. staticDecode :: Typeable a => Static (SerializableDict a) -> Static (ByteString -> a) staticDecode dict = $(mkStatic 'decodeDict) `staticApply` dict -- | Convert a static value into a closure. staticClosure :: forall a. Typeable a => Static a -> Closure a staticClosure static = Closure (staticConst `staticApply` static) empty -- | Convert a serializable value into a closure. toClosure :: forall a. Serializable a => Static (SerializableDict a) -> a -> Closure a toClosure dict x = Closure (staticDecode dict) (encode x)