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
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.
14module Control.Distributed.Static
15 ( -- * Introducing static values
21 -- * Eliminating static values
42 -- * Combinators on static values
46 -- * Combinators on closures
60import Prelude hiding (id, (.))
67import Data.Maybe (fromJust)
77import Data.ByteString.Lazy (ByteString, empty)
79import qualified Data.Map as Map (lookup, empty, insert)
80import Control.Applicative ((<$>), (<*>))
81import Control.Category (Category(id, (.)))
82import qualified Control.Arrow as Arrow (first, second, (***), app)
83import Control.Distributed.Static.Internal.Dynamic
93import Control.Distributed.Static.Internal.TypeRep (compareTypeRep)
95--------------------------------------------------------------------------------
96-- Introducing static values --
97--------------------------------------------------------------------------------
100 StaticLabel String TypeRep
101 | StaticApply StaticLabel StaticLabel
102 | StaticDuplicate StaticLabel TypeRep
103 deriving (Typeable, Show)
105-- | A static value. Static is opaque; see 'staticLabel', 'staticApply',
106-- 'staticDuplicate' or 'staticTypeOf'.
107newtype Static a = Static StaticLabel
108 deriving (Typeable, Show)
110instance Typeable a => Binary (Static a) where
111 put (Static label) = putStaticLabel label
113 label <- getStaticLabel
114 if typeOfStaticLabel label `compareTypeRep` typeOf (undefined :: a)
115 then return $ Static label
116 else fail "Static.get: type error"
118-- We don't want StaticLabel to be its own Binary instance
119putStaticLabel :: StaticLabel -> Put
120putStaticLabel (StaticLabel string typ) =
121 putWord8 0 >> put string >> put typ
122putStaticLabel (StaticApply label1 label2) =
123 putWord8 1 >> putStaticLabel label1 >> putStaticLabel label2
124putStaticLabel (StaticDuplicate label typ) =
125 putWord8 2 >> putStaticLabel label >> put typ
127getStaticLabel :: Get StaticLabel
131 0 -> StaticLabel <$> get <*> get
132 1 -> StaticApply <$> getStaticLabel <*> getStaticLabel
133 2 -> StaticDuplicate <$> getStaticLabel <*> get
134 _ -> fail "StaticLabel.get: invalid"
136-- | Create a primitive static value.
138-- It is the responsibility of the client code to make sure the corresponding
139-- entry in the 'RemoteTable' has the appropriate type.
140staticLabel :: forall a. Typeable a => String -> Static a
141staticLabel label = Static (StaticLabel label (typeOf (undefined :: a)))
143-- | Apply two static values
144staticApply :: Static (a -> b) -> Static a -> Static b
145staticApply (Static f) (Static x) = Static (StaticApply f x)
147-- | Co-monadic 'duplicate' for static values
148staticDuplicate :: forall a. Typeable a => Static a -> Static (Static a)
149staticDuplicate (Static x) =
150 Static (StaticDuplicate x (typeOf (undefined :: Static a)))
152-- | @staticTypeOf (x :: a)@ mimicks @static (undefined :: a)@ -- even if
153-- @x@ is not static, the type of @x@ always is.
154staticTypeOf :: forall a. Typeable a => a -> Static a
155staticTypeOf _ = Static (StaticLabel "$undefined" (typeOf (undefined :: a)))
157typeOfStaticLabel :: StaticLabel -> TypeRep
158typeOfStaticLabel (StaticLabel _ typ)
160typeOfStaticLabel (StaticApply f x)
161 = fromJust $ funResultTy (typeOfStaticLabel f) (typeOfStaticLabel x)
162typeOfStaticLabel (StaticDuplicate _ typ)
165--------------------------------------------------------------------------------
166-- Eliminating static values --
167--------------------------------------------------------------------------------
169-- | Runtime dictionary for 'unstatic' lookups
170newtype RemoteTable = RemoteTable (Map String Dynamic)
172-- | Initial remote table
173initRemoteTable :: RemoteTable
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
192 compose :: (b -> c) -> (a -> b) -> a -> c
195 first :: (a -> b) -> (a, c) -> (b, c)
198 second :: (a -> b) -> (c, a) -> (c, b)
199 second = Arrow.second
201 split :: (a -> b) -> (a' -> b') -> (a, a') -> (b, b')
204 decodeEnvPair :: ByteString -> (ByteString, ByteString)
205 decodeEnvPair = decode
207 app :: (a -> b, a) -> b
210-- | Register a static label
211registerStatic :: String -> Dynamic -> RemoteTable -> RemoteTable
212registerStatic label dyn (RemoteTable rtable)
213 = RemoteTable (Map.insert label dyn rtable)
215-- | Resolve a Static value.
216resolveStatic :: RemoteTable -> Static a -> Maybe Dynamic
217resolveStatic (RemoteTable rtable) (Static (StaticLabel string typ)) = do
218 unsafeCastDyn (const typ) <$> Map.lookup string rtable
219resolveStatic rtable (Static (StaticApply static1 static2)) = do
220 f <- resolveStatic rtable (Static static1)
221 x <- resolveStatic rtable (Static static2)
223resolveStatic _rtable (Static (StaticDuplicate static typ)) =
224 return . unsafeCastDyn (const typ) $ unsafeToDyn (Static static)
226--------------------------------------------------------------------------------
228--------------------------------------------------------------------------------
230-- | A closure is a static value and an encoded environment
231data Closure a = Closure (Static (ByteString -> a)) ByteString
232 deriving (Typeable, Show)
234instance Typeable a => Binary (Closure a) where
235 put (Closure static env) = put static >> put env
236 get = Closure <$> get <*> get
238-- | Convert a static value into a closure.
239staticClosure :: forall a. Typeable a => Static a -> Closure a
240staticClosure static = Closure (staticConst static) empty
242-- | Resolve a Closure
243resolveClosure :: RemoteTable -> Static a -> ByteString -> Maybe Dynamic
244resolveClosure rtable static env = do
245 decoder <- resolveStatic rtable static
246 decoder `dynApply` toDyn env
248--------------------------------------------------------------------------------
249-- Predefined static values --
250--------------------------------------------------------------------------------
252-- | Static version of 'id'
253idStatic :: (Typeable a)
255idStatic = staticLabel "$id"
257-- | Static version of ('Prelude..')
258composeStatic :: (Typeable a, Typeable b, Typeable c)
259 => Static ((b -> c) -> (a -> b) -> a -> c)
260composeStatic = staticLabel "$compose"
262-- | Static version of 'const'
263constStatic :: (Typeable a, Typeable b)
264 => Static (a -> b -> a)
265constStatic = staticLabel "$const"
267-- | Static version of 'flip'
268flipStatic :: (Typeable a, Typeable b, Typeable c)
269 => Static ((a -> b -> c) -> b -> a -> c)
270flipStatic = staticLabel "$flip"
272-- | Static version of 'fst'
273fstStatic :: (Typeable a, Typeable b)
274 => Static ((a, b) -> a)
275fstStatic = staticLabel "$fst"
277-- | Static version of 'snd'
278sndStatic :: (Typeable a, Typeable b)
279 => Static ((a, b) -> b)
280sndStatic = staticLabel "$snd"
282-- | Static version of 'Arrow.first'
283firstStatic :: (Typeable a, Typeable b, Typeable c)
284 => Static ((a -> b) -> (a, c) -> (b, c))
285firstStatic = staticLabel "$first"
287-- | Static version of 'Arrow.second'
288secondStatic :: (Typeable a, Typeable b, Typeable c)
289 => Static ((a -> b) -> (c, a) -> (c, b))
290secondStatic = staticLabel "$second"
292-- | Static version of ('Arrow.***')
293splitStatic :: (Typeable a, Typeable a', Typeable b, Typeable b')
294 => Static ((a -> b) -> (a' -> b') -> (a, a') -> (b, b'))
295splitStatic = staticLabel "$split"
297-- | Static version of @()@
298unitStatic :: Static ()
299unitStatic = staticLabel "$unit"
301-- | Static version of 'Arrow.app'
302appStatic :: (Typeable a, Typeable b)
303 => Static ((a -> b, a) -> b)
304appStatic = staticLabel "$app"
306--------------------------------------------------------------------------------
307-- Combinators on static values --
308--------------------------------------------------------------------------------
310staticCompose :: (Typeable a, Typeable b, Typeable c)
311 => Static (b -> c) -> Static (a -> b) -> Static (a -> c)
312staticCompose g f = composeStatic `staticApply` g `staticApply` f
314staticSplit :: (Typeable a, Typeable a', Typeable b, Typeable b')
315 => Static (a -> b) -> Static (a' -> b') -> Static ((a, a') -> (b, b'))
316staticSplit f g = splitStatic `staticApply` f `staticApply` g
318staticConst :: (Typeable a, Typeable b)
319 => Static a -> Static (b -> a)
320staticConst x = constStatic `staticApply` x
322--------------------------------------------------------------------------------
323-- Combinators on Closures --
324--------------------------------------------------------------------------------
326closureApplyStatic :: forall a b. (Typeable a, Typeable b)
327 => Static (a -> b) -> Closure a -> Closure b
328closureApplyStatic f (Closure decoder env) =
329 Closure (f `staticCompose` decoder) env
331decodeEnvPairStatic :: Static (ByteString -> (ByteString, ByteString))
332decodeEnvPairStatic = staticLabel "$decodeEnvPair"
334closureApply :: forall a b. (Typeable a, Typeable b)
335 => Closure (a -> b) -> Closure a -> Closure b
336closureApply (Closure fdec fenv) (Closure xdec xenv) =
337 Closure decoder (encode (fenv, xenv))
339 decoder :: Static (ByteString -> b)
342 (fdec `staticSplit` xdec)
346closureCompose :: (Typeable a, Typeable b, Typeable c)
347 => Closure (b -> c) -> Closure (a -> b) -> Closure (a -> c)
348closureCompose g f = composeStatic `closureApplyStatic` g `closureApply` f
350closureSplit :: (Typeable a, Typeable a', Typeable b, Typeable b')
351 => Closure (a -> b) -> Closure (a' -> b') -> Closure ((a, a') -> (b, b'))
352closureSplit f g = splitStatic `closureApplyStatic` f `closureApply` g
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list