Remove unsafeCoerce-importing kludgery in favor of Unsafe.Coerce
[ghc.git] / libraries / base / Data / Dynamic.hs
1 {-# OPTIONS_GHC -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 dynTypeRep
39
40 ) where
41
42
43 import Data.Typeable
44 import Data.Maybe
45 import Unsafe.Coerce
46
47 #ifdef __GLASGOW_HASKELL__
48 import GHC.Base
49 import GHC.Show
50 import GHC.Err
51 import GHC.Num
52 #endif
53
54 #ifdef __HUGS__
55 import Hugs.Prelude
56 import Hugs.IO
57 import Hugs.IORef
58 import Hugs.IOExts
59 #endif
60
61 #ifdef __NHC__
62 import NHC.IOExtras (IORef,newIORef,readIORef,writeIORef,unsafePerformIO)
63 #endif
64
65 #include "Typeable.h"
66
67 -------------------------------------------------------------
68 --
69 -- The type Dynamic
70 --
71 -------------------------------------------------------------
72
73 {-|
74 A value of type 'Dynamic' is an object encapsulated together with its type.
75
76 A 'Dynamic' may only represent a monomorphic value; an attempt to
77 create a value of type 'Dynamic' from a polymorphically-typed
78 expression will result in an ambiguity error (see 'toDyn').
79
80 'Show'ing a value of type 'Dynamic' returns a pretty-printed representation
81 of the object\'s type; useful for debugging.
82 -}
83 #ifndef __HUGS__
84 data Dynamic = Dynamic TypeRep Obj
85 #endif
86
87 INSTANCE_TYPEABLE0(Dynamic,dynamicTc,"Dynamic")
88
89 instance Show Dynamic where
90 -- the instance just prints the type representation.
91 showsPrec _ (Dynamic t _) =
92 showString "<<" .
93 showsPrec 0 t .
94 showString ">>"
95
96 #ifdef __GLASGOW_HASKELL__
97 type Obj = Any
98 -- Use GHC's primitive 'Any' type to hold the dynamically typed value.
99 --
100 -- In GHC's new eval/apply execution model this type must not look
101 -- like a data type. If it did, GHC would use the constructor convention
102 -- when evaluating it, and this will go wrong if the object is really a
103 -- function. Using Any forces GHC to use
104 -- a fallback convention for evaluating it that works for all types.
105 #elif !defined(__HUGS__)
106 data Obj = Obj
107 #endif
108
109 -- | Converts an arbitrary value into an object of type 'Dynamic'.
110 --
111 -- The type of the object must be an instance of 'Typeable', which
112 -- ensures that only monomorphically-typed objects may be converted to
113 -- 'Dynamic'. To convert a polymorphic object into 'Dynamic', give it
114 -- a monomorphic type signature. For example:
115 --
116 -- > toDyn (id :: Int -> Int)
117 --
118 toDyn :: Typeable a => a -> Dynamic
119 toDyn v = Dynamic (typeOf v) (unsafeCoerce v)
120
121 -- | Converts a 'Dynamic' object back into an ordinary Haskell value of
122 -- the correct type. See also 'fromDynamic'.
123 fromDyn :: Typeable a
124 => Dynamic -- ^ the dynamically-typed object
125 -> a -- ^ a default value
126 -> a -- ^ returns: the value of the first argument, if
127 -- it has the correct type, otherwise the value of
128 -- the second argument.
129 fromDyn (Dynamic t v) def
130 | typeOf def == t = unsafeCoerce v
131 | otherwise = def
132
133 -- | Converts a 'Dynamic' object back into an ordinary Haskell value of
134 -- the correct type. See also 'fromDyn'.
135 fromDynamic
136 :: Typeable a
137 => Dynamic -- ^ the dynamically-typed object
138 -> Maybe a -- ^ returns: @'Just' a@, if the dynamically-typed
139 -- object has the correct type (and @a@ is its value),
140 -- or 'Nothing' otherwise.
141 fromDynamic (Dynamic t v) =
142 case unsafeCoerce v of
143 r | t == typeOf r -> Just r
144 | otherwise -> Nothing
145
146 -- (f::(a->b)) `dynApply` (x::a) = (f a)::b
147 dynApply :: Dynamic -> Dynamic -> Maybe Dynamic
148 dynApply (Dynamic t1 f) (Dynamic t2 x) =
149 case funResultTy t1 t2 of
150 Just t3 -> Just (Dynamic t3 ((unsafeCoerce f) x))
151 Nothing -> Nothing
152
153 dynApp :: Dynamic -> Dynamic -> Dynamic
154 dynApp f x = case dynApply f x of
155 Just r -> r
156 Nothing -> error ("Type error in dynamic application.\n" ++
157 "Can't apply function " ++ show f ++
158 " to argument " ++ show x)
159
160 dynTypeRep :: Dynamic -> TypeRep
161 dynTypeRep (Dynamic tr _) = tr