2 % (c) AQUA Project, Glasgow University, 1998
5 Cheap and cheerful dynamic types.
7 The Dynamic interface is part of the Hugs/GHC standard
8 libraries, providing basic support for dynamic types.
10 Operations for injecting values of arbitrary type into
11 a dynamically typed value, Dynamic, are provided, together
12 with operations for converting dynamic values into a concrete
15 The Dynamic implementation provided is closely based on code
16 contained in Hugs library of the same name.
22 Dynamic -- abstract, instance of: Show (?)
23 , toDyn -- :: Typeable a => a -> Dynamic
24 , fromDyn -- :: Typeable a => Dynamic -> a -> a
25 , fromDynamic -- :: Typeable a => Dynamic -> Maybe a
27 -- type representation
30 -- class Typeable a where { typeOf :: a -> TypeRep }
32 -- Dynamic defines Typeable instances for the following
33 -- Prelude types: Char, Int, Float, Double, Bool
34 -- (), Maybe a, (a->b), [a]
35 -- (a,b) (a,b,c) (a,b,c,d) (a,b,c,d,e)
37 , TypeRep -- abstract, instance of: Eq, Show
38 , TyCon -- abstract, instance of: Eq, Show
40 -- type representation constructors/operators:
41 , mkTyCon -- :: String -> TyCon
42 , mkAppTy -- :: TyCon -> [TypeRep] -> TypeRep
43 , mkFunTy -- :: TypeRep -> TypeRep -> TypeRep
44 , applyTy -- :: TypeRep -> TypeRep -> Maybe TypeRep
47 -- let iTy = mkTyCon "Int" in show (mkAppTy (mkTyCon ",,")
50 -- returns "(Int,Int,Int)"
52 -- The TypeRep Show instance promises to print tuple types
53 -- correctly. Tuple type constructors are specified by a
54 -- sequence of commas, e.g., (mkTyCon ",,,,,,") returns
65 IORef, newIORef, readIORef, writeIORef
72 unsafeCoerce = primUnsafeCoerce
76 unsafeCoerce :: a -> b
77 unsafeCoerce = unsafeCoerce#
81 The dynamic type is represented by Dynamic, carrying
82 the dynamic value along with its type representation:
85 -- the instance just prints the type representation.
86 instance Show Dynamic where
87 showsPrec _ (Dynamic t _) =
93 Operations for going to and from Dynamic:
96 toDyn :: Typeable a => a -> Dynamic
97 toDyn v = Dynamic (typeOf v) (unsafeCoerce v)
99 fromDyn :: Typeable a => Dynamic -> a -> a
100 fromDyn (Dynamic t v) def
101 | typeOf def == t = unsafeCoerce v
104 fromDynamic :: Typeable a => Dynamic -> Maybe a
105 fromDynamic (Dynamic t v) =
106 case unsafeCoerce v of
107 r | t == typeOf r -> Just r
108 | otherwise -> Nothing
111 (Abstract) universal datatype:
114 instance Show TypeRep where
115 showsPrec p (App tycon tys) =
117 [] -> showsPrec p tycon
118 [x] | tycon == listTc -> showChar '[' . shows x . showChar ']'
119 xs | isTupleTyCon tycon -> showTuple tycon xs
120 xs -> showParen (p > 9) $
121 showsPrec p tycon . showChar ' ' . showArgs tys
122 showsPrec p (Fun f a) =
124 showsPrec 9 f . showString " -> " . showsPrec 8 a
127 To make it possible to convert values with user-defined types
128 into type Dynamic, we need a systematic way of getting
129 the type representation of an arbitrary type. Type class
130 provide a good fit, here
133 class Typeable a where
134 typeOf :: a -> TypeRep
137 NOTE: The argument to the overloaded `typeOf' is only
138 used to carry type information, and Typeable instances
139 should *never* look at its value.
142 isTupleTyCon :: TyCon -> Bool
143 isTupleTyCon (TyCon _ (',':_)) = True
144 isTupleTyCon _ = False
146 instance Show TyCon where
147 showsPrec d (TyCon _ s) = showString s
150 -- If we enforce the restriction that TyCons are
151 -- shared, we can map them onto Ints very simply
152 -- which allows for efficient comparison.
154 mkTyCon :: String -> TyCon
155 mkTyCon str = unsafePerformIO $ do
161 uni = unsafePerformIO ( newIORef 0 )
164 Some (Show.TypeRep) helpers:
168 showArgs [a] = showsPrec 10 a
169 showArgs (a:as) = showsPrec 10 a . showString " " . showArgs as
171 showTuple :: TyCon -> [TypeRep] -> ShowS
172 showTuple (TyCon _ str) args = showChar '(' . go str args
174 go [] [a] = showsPrec 10 a . showChar ')'
175 go _ [] = showChar ')' -- a failure condition, really.
176 go (',':xs) (a:as) = showsPrec 10 a . showChar ',' . go xs as
177 go _ _ = showChar ')'
181 mkAppTy :: TyCon -> [TypeRep] -> TypeRep
182 mkAppTy tyc args = App tyc args
184 mkFunTy :: TypeRep -> TypeRep -> TypeRep
185 mkFunTy f a = Fun f a
191 -- (f::(a->b)) `dynApply` (x::a) = (f a)::b
192 dynApply :: Dynamic -> Dynamic -> Maybe Dynamic
193 dynApply (Dynamic t1 f) (Dynamic t2 x) =
194 case applyTy t1 t2 of
195 Just t3 -> Just (Dynamic t3 ((unsafeCoerce f) x))
198 dynApp :: Dynamic -> Dynamic -> Dynamic
199 dynApp f x = case dynApply f x of
201 Nothing -> error ("Type error in dynamic application.\n" ++
202 "Can't apply function " ++ show f ++
203 " to argument " ++ show x)
205 applyTy :: TypeRep -> TypeRep -> Maybe TypeRep
206 applyTy (Fun t1 t2) t3
208 applyTy _ _ = Nothing
213 instance Typeable Int where
214 typeOf _ = mkAppTy intTc []
216 instance Typeable Char where
217 typeOf _ = mkAppTy charTc []
219 instance Typeable Bool where
220 typeOf _ = mkAppTy boolTc []
222 instance Typeable Float where
223 typeOf _ = mkAppTy floatTc []
225 instance Typeable Double where
226 typeOf _ = mkAppTy doubleTc []
228 instance Typeable Integer where
229 typeOf _ = mkAppTy integerTc []
231 instance Typeable a => Typeable (IO a) where
232 typeOf action = mkAppTy ioTc [typeOf (doIO action)]
237 instance Typeable a => Typeable [a] where
238 typeOf ls = mkAppTy listTc [typeOf (hd ls)]
243 instance Typeable a => Typeable (Maybe a) where
244 typeOf mb = mkAppTy maybeTc [typeOf (getJ mb)]
249 instance (Typeable a, Typeable b) => Typeable (Either a b) where
250 typeOf ei = mkAppTy maybeTc [typeOf (getL ei), typeOf (getR ei)]
252 getL :: Either a b -> a
254 getR :: Either a b -> a
257 instance (Typeable a, Typeable b) => Typeable (a -> b) where
258 typeOf f = mkFunTy (typeOf (arg f)) (typeOf (res f))
266 instance Typeable () where
267 typeOf _ = mkAppTy unitTc []
269 instance Typeable TypeRep where
270 typeOf _ = mkAppTy typeRepTc []
272 instance Typeable TyCon where
273 typeOf _ = mkAppTy tyConTc []
275 instance Typeable Dynamic where
276 typeOf _ = mkAppTy dynamicTc []
278 instance Typeable Ordering where
279 typeOf _ = mkAppTy orderingTc []
281 instance (Typeable a, Typeable b) => Typeable (a,b) where
282 typeOf tu = mkAppTy tup2Tc [typeOf (fst tu), typeOf (snd tu)]
291 instance ( Typeable a
293 , Typeable c) => Typeable (a,b,c) where
294 typeOf tu = mkAppTy tup3Tc [ typeOf (fst tu)
306 tup3Tc = mkTyCon ",,"
308 instance ( Typeable a
311 , Typeable d) => Typeable (a,b,c,d) where
312 typeOf tu = mkAppTy tup4Tc [ typeOf (fst tu)
318 fst :: (a,b,c,d) -> a
320 snd :: (a,b,c,d) -> b
322 thd :: (a,b,c,d) -> c
324 fth :: (a,b,c,d) -> d
327 tup4Tc = mkTyCon ",,,"
329 instance ( Typeable a
333 , Typeable e) => Typeable (a,b,c,d,e) where
334 typeOf tu = mkAppTy tup5Tc [ typeOf (fst tu)
341 fst :: (a,b,c,d,e) -> a
343 snd :: (a,b,c,d,e) -> b
345 thd :: (a,b,c,d,e) -> c
347 fth :: (a,b,c,d,e) -> d
349 ffth :: (a,b,c,d,e) -> e
352 tup5Tc = mkTyCon ",,,,"
356 @TyCon@s are provided for the following:
360 intTc = mkTyCon "Int"
361 charTc = mkTyCon "Char"
362 boolTc = mkTyCon "Bool"
363 floatTc = mkTyCon "Float"
364 doubleTc = mkTyCon "Double"
365 integerTc = mkTyCon "Integer"
367 maybeTc = mkTyCon "Maybe"
368 eitherTc = mkTyCon "Either"
369 listTc = mkTyCon "[]"
370 unitTc = mkTyCon "()"
371 orderingTc = mkTyCon "Ordering"
372 arrayTc = mkTyCon "Array"
373 complexTc = mkTyCon "Complex"
374 handleTc = mkTyCon "Handle"
376 -- Hugs/GHC extension lib types:
377 addrTc = mkTyCon "Addr"
378 stablePtrTc = mkTyCon "StablePtr"
379 mvarTc = mkTyCon "MVar"
380 foreignObjTc = mkTyCon "ForeignObj"
382 int8Tc = mkTyCon "Int8"
383 int16Tc = mkTyCon "Int16"
384 int32Tc = mkTyCon "Int32"
385 int64Tc = mkTyCon "Int64"
386 word8Tc = mkTyCon "Word8"
387 word16Tc = mkTyCon "Word16"
388 word32Tc = mkTyCon "Word32"
389 word64Tc = mkTyCon "Word64"
390 tyConTc = mkTyCon "TyCon"
391 typeRepTc = mkTyCon "Type"
392 dynamicTc = mkTyCon "Dynamic"
396 byteArrayTc = mkTyCon "ByteArray"
397 mutablebyteArrayTc = mkTyCon "MutableByteArray"
398 wordTc = mkTyCon "Word"
404 test1 = toDyn (1::Int)
405 test2 = toDyn ((+) :: Int -> Int -> Int)
406 test3 = dynApp test2 test1
407 test4 = dynApp test3 test1
409 test5, test6,test7 :: Int
410 test5 = fromDyn test4 0
411 test6 = fromDyn test1 0
412 test7 = fromDyn test2 0
414 test8 = toDyn (mkAppTy listTc)
416 test9 = fromDyn test8 0
418 printf :: String -> [Dynamic] -> IO ()
419 printf str args = putStr (decode str args)
422 decode ('%':'n':cs) (d:ds) =
423 (\ v -> show v++decode cs ds) (fromDyn d (0::Int))
424 decode ('%':'c':cs) (d:ds) =
425 (\ v -> show v++decode cs ds) (fromDyn d ('\0'))
426 decode ('%':'b':cs) (d:ds) =
427 (\ v -> show v++decode cs ds) (fromDyn d (False::Bool))
428 decode (x:xs) ds = x:decode xs ds
431 test10 = printf "%n = %c, that much is %b\n" [toDyn (3::Int),toDyn 'a', toDyn False]