b3f935080c7f80ea92a871ac1f86059a996b575b
[packages/base.git] / Data / Dynamic.hs
1 {-# LANGUAGE Trustworthy #-}
2 {-# LANGUAGE CPP, NoImplicitPrelude #-}
3 #ifdef __GLASGOW_HASKELL__
4 {-# LANGUAGE DeriveDataTypeable, StandaloneDeriving #-}
5 #endif
6
7 -----------------------------------------------------------------------------
8 -- |
9 -- Module : Data.Dynamic
10 -- Copyright : (c) The University of Glasgow 2001
11 -- License : BSD-style (see the file libraries/base/LICENSE)
12 --
13 -- Maintainer : libraries@haskell.org
14 -- Stability : experimental
15 -- Portability : portable
16 --
17 -- The Dynamic interface provides basic support for dynamic types.
18 --
19 -- Operations for injecting values of arbitrary type into
20 -- a dynamically typed value, Dynamic, are provided, together
21 -- with operations for converting dynamic values into a concrete
22 -- (monomorphic) type.
23 --
24 -----------------------------------------------------------------------------
25
26 module Data.Dynamic
27 (
28
29 -- Module Data.Typeable re-exported for convenience
30 module Data.Typeable,
31
32 -- * The @Dynamic@ type
33 Dynamic, -- abstract, instance of: Show, Typeable
34
35 -- * Converting to and from @Dynamic@
36 toDyn, -- :: Typeable a => a -> Dynamic
37 fromDyn, -- :: Typeable a => Dynamic -> a -> a
38 fromDynamic, -- :: Typeable a => Dynamic -> Maybe a
39
40 -- * Applying functions of dynamic type
41 dynApply,
42 dynApp,
43 dynTypeRep
44
45 ) where
46
47
48 import Data.Typeable
49 import Data.Maybe
50 import Unsafe.Coerce
51
52 #ifdef __GLASGOW_HASKELL__
53 import GHC.Base
54 import GHC.Show
55 import GHC.Exception
56 #endif
57
58 #ifdef __HUGS__
59 import Hugs.Prelude
60 import Hugs.IO
61 import Hugs.IORef
62 import Hugs.IOExts
63 #endif
64
65 #ifdef __NHC__
66 import NHC.IOExtras (IORef,newIORef,readIORef,writeIORef,unsafePerformIO)
67 #endif
68
69 #include "Typeable.h"
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 INSTANCE_TYPEABLE0(Dynamic,dynamicTc,"Dynamic")
92
93 instance Show Dynamic where
94 -- the instance just prints the type representation.
95 showsPrec _ (Dynamic t _) =
96 showString "<<" .
97 showsPrec 0 t .
98 showString ">>"
99
100 #ifdef __GLASGOW_HASKELL__
101 -- here so that it isn't an orphan:
102 instance Exception Dynamic
103 #endif
104
105 #ifdef __GLASGOW_HASKELL__
106 type Obj = Any
107 -- Use GHC's primitive 'Any' type to hold the dynamically typed value.
108 --
109 -- In GHC's new eval/apply execution model this type must not look
110 -- like a data type. If it did, GHC would use the constructor convention
111 -- when evaluating it, and this will go wrong if the object is really a
112 -- function. Using Any forces GHC to use
113 -- a fallback convention for evaluating it that works for all types.
114 #elif !defined(__HUGS__)
115 data Obj = Obj
116 #endif
117
118 -- | Converts an arbitrary value into an object of type 'Dynamic'.
119 --
120 -- The type of the object must be an instance of 'Typeable', which
121 -- ensures that only monomorphically-typed objects may be converted to
122 -- 'Dynamic'. To convert a polymorphic object into 'Dynamic', give it
123 -- a monomorphic type signature. For example:
124 --
125 -- > toDyn (id :: Int -> Int)
126 --
127 toDyn :: Typeable a => a -> Dynamic
128 toDyn v = Dynamic (typeOf v) (unsafeCoerce v)
129
130 -- | Converts a 'Dynamic' object back into an ordinary Haskell value of
131 -- the correct type. See also 'fromDynamic'.
132 fromDyn :: Typeable a
133 => Dynamic -- ^ the dynamically-typed object
134 -> a -- ^ a default value
135 -> a -- ^ returns: the value of the first argument, if
136 -- it has the correct type, otherwise the value of
137 -- the second argument.
138 fromDyn (Dynamic t v) def
139 | typeOf def == t = unsafeCoerce v
140 | otherwise = def
141
142 -- | Converts a 'Dynamic' object back into an ordinary Haskell value of
143 -- the correct type. See also 'fromDyn'.
144 fromDynamic
145 :: Typeable a
146 => Dynamic -- ^ the dynamically-typed object
147 -> Maybe a -- ^ returns: @'Just' a@, if the dynamically-typed
148 -- object has the correct type (and @a@ is its value),
149 -- or 'Nothing' otherwise.
150 fromDynamic (Dynamic t v) =
151 case unsafeCoerce v of
152 r | t == typeOf r -> Just r
153 | otherwise -> Nothing
154
155 -- (f::(a->b)) `dynApply` (x::a) = (f a)::b
156 dynApply :: Dynamic -> Dynamic -> Maybe Dynamic
157 dynApply (Dynamic t1 f) (Dynamic t2 x) =
158 case funResultTy t1 t2 of
159 Just t3 -> Just (Dynamic t3 ((unsafeCoerce f) x))
160 Nothing -> Nothing
161
162 dynApp :: Dynamic -> Dynamic -> Dynamic
163 dynApp f x = case dynApply f x of
164 Just r -> r
165 Nothing -> error ("Type error in dynamic application.\n" ++
166 "Can't apply function " ++ show f ++
167 " to argument " ++ show x)
168
169 dynTypeRep :: Dynamic -> TypeRep
170 dynTypeRep (Dynamic tr _) = tr