[project @ 2004-03-21 19:07:00 by ralf]
[packages/random.git] / Data / Dynamic.hs
1 {-# OPTIONS -fno-implicit-prelude #-}
2 -----------------------------------------------------------------------------
3 -- |
4 -- Module : Data.Dynamic
5 -- Copyright : (c) The University of Glasgow 2001
6 -- License : BSD-style (see the file libraries/base/LICENSE)
7 --
8 -- Maintainer : libraries@haskell.org
9 -- Stability : experimental
10 -- Portability : portable
11 --
12 -- The Dynamic interface provides basic support for dynamic types.
13 --
14 -- Operations for injecting values of arbitrary type into
15 -- a dynamically typed value, Dynamic, are provided, together
16 -- with operations for converting dynamic values into a concrete
17 -- (monomorphic) type.
18 --
19 -----------------------------------------------------------------------------
20
21 module Data.Dynamic
22 (
23
24 -- Module Data.Typeable re-exported for convenience
25 module Data.Typeable,
26
27 -- * The @Dynamic@ type
28 Dynamic, -- abstract, instance of: Show, Typeable
29
30 -- * Converting to and from @Dynamic@
31 toDyn, -- :: Typeable a => a -> Dynamic
32 fromDyn, -- :: Typeable a => Dynamic -> a -> a
33 fromDynamic, -- :: Typeable a => Dynamic -> Maybe a
34
35 -- * Applying functions of dynamic type
36 dynApply,
37 dynApp
38
39 ) where
40
41
42 import Data.Typeable
43 import Data.Maybe
44
45 #ifdef __GLASGOW_HASKELL__
46 import GHC.Base
47 import GHC.Show
48 import GHC.Err
49 import GHC.Num
50 #endif
51
52 #ifdef __HUGS__
53 import Hugs.Prelude
54 import Hugs.IO
55 import Hugs.IORef
56 import Hugs.IOExts
57 #endif
58
59 #ifdef __GLASGOW_HASKELL__
60 unsafeCoerce :: a -> b
61 unsafeCoerce = unsafeCoerce#
62 #endif
63
64 #ifdef __NHC__
65 import NonStdUnsafeCoerce (unsafeCoerce)
66 import NHC.IOExtras (IORef,newIORef,readIORef,writeIORef,unsafePerformIO)
67 #else
68 #include "Typeable.h"
69 #endif
70
71 -------------------------------------------------------------
72 --
73 -- The type Dynamic
74 --
75 -------------------------------------------------------------
76
77 {-|
78 A value of type 'Dynamic' is an object encapsulated together with its type.
79
80 A 'Dynamic' may only represent a monomorphic value; an attempt to
81 create a value of type 'Dynamic' from a polymorphically-typed
82 expression will result in an ambiguity error (see 'toDyn').
83
84 'Show'ing a value of type 'Dynamic' returns a pretty-printed representation
85 of the object\'s type; useful for debugging.
86 -}
87 #ifndef __HUGS__
88 data Dynamic = Dynamic TypeRep Obj
89 #endif
90
91 #ifndef __NHC__
92 INSTANCE_TYPEABLE0(Dynamic,dynamicTc,"Dynamic")
93 #endif
94
95 instance Show Dynamic where
96 -- the instance just prints the type representation.
97 showsPrec _ (Dynamic t _) =
98 showString "<<" .
99 showsPrec 0 t .
100 showString ">>"
101
102 #ifdef __GLASGOW_HASKELL__
103 type Obj = forall a . a
104 -- Dummy type to hold the dynamically typed value.
105 --
106 -- In GHC's new eval/apply execution model this type must
107 -- be polymorphic. It can't be a constructor, because then
108 -- GHC will use the constructor convention when evaluating it,
109 -- and this will go wrong if the object is really a function. On
110 -- the other hand, if we use a polymorphic type, GHC will use
111 -- a fallback convention for evaluating it that works for all types.
112 -- (using a function type here would also work).
113 #elif !defined(__HUGS__)
114 data Obj = Obj
115 #endif
116
117 -- | Converts an arbitrary value into an object of type 'Dynamic'.
118 --
119 -- The type of the object must be an instance of 'Typeable', which
120 -- ensures that only monomorphically-typed objects may be converted to
121 -- 'Dynamic'. To convert a polymorphic object into 'Dynamic', give it
122 -- a monomorphic type signature. For example:
123 --
124 -- > toDyn (id :: Int -> Int)
125 --
126 toDyn :: Typeable a => a -> Dynamic
127 toDyn v = Dynamic (typeOf v) (unsafeCoerce v)
128
129 -- | Converts a 'Dynamic' object back into an ordinary Haskell value of
130 -- the correct type. See also 'fromDynamic'.
131 fromDyn :: Typeable a
132 => Dynamic -- ^ the dynamically-typed object
133 -> a -- ^ a default value
134 -> a -- ^ returns: the value of the first argument, if
135 -- it has the correct type, otherwise the value of
136 -- the second argument.
137 fromDyn (Dynamic t v) def
138 | typeOf def == t = unsafeCoerce v
139 | otherwise = def
140
141 -- | Converts a 'Dynamic' object back into an ordinary Haskell value of
142 -- the correct type. See also 'fromDyn'.
143 fromDynamic
144 :: Typeable a
145 => Dynamic -- ^ the dynamically-typed object
146 -> Maybe a -- ^ returns: @'Just' a@, if the dyanmically-typed
147 -- object has the correct type (and @a@ is its value),
148 -- or 'Nothing' otherwise.
149 fromDynamic (Dynamic t v) =
150 case unsafeCoerce v of
151 r | t == typeOf r -> Just r
152 | otherwise -> Nothing
153
154 -- (f::(a->b)) `dynApply` (x::a) = (f a)::b
155 dynApply :: Dynamic -> Dynamic -> Maybe Dynamic
156 dynApply (Dynamic t1 f) (Dynamic t2 x) =
157 case funResultTy t1 t2 of
158 Just t3 -> Just (Dynamic t3 ((unsafeCoerce f) x))
159 Nothing -> Nothing
160
161 dynApp :: Dynamic -> Dynamic -> Dynamic
162 dynApp f x = case dynApply f x of
163 Just r -> r
164 Nothing -> error ("Type error in dynamic application.\n" ++
165 "Can't apply function " ++ show f ++
166 " to argument " ++ show x)