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.
18 NOTE: test code at the end, but commented out.
24 Dynamic -- abstract, instance of: Show (?)
25 , toDyn -- :: Typeable a => a -> Dynamic
26 , fromDyn -- :: Typeable a => Dynamic -> a -> a
27 , fromDynamic -- :: Typeable a => Dynamic -> Maybe a
29 -- type representation
32 -- class Typeable a where { typeOf :: a -> TypeRep }
34 -- Dynamic defines Typeable instances for the following
35 -- Prelude types: Char, Int, Float, Double, Bool
36 -- (), Maybe a, (a->b), [a]
37 -- (a,b) (a,b,c) (a,b,c,d) (a,b,c,d,e)
39 , TypeRep -- abstract, instance of: Eq, Show
40 , TyCon -- abstract, instance of: Eq, Show
42 -- type representation constructors/operators:
43 , mkTyCon -- :: String -> TyCon
44 , mkAppTy -- :: TyCon -> [TypeRep] -> TypeRep
45 , mkFunTy -- :: TypeRep -> TypeRep -> TypeRep
46 , applyTy -- :: TypeRep -> TypeRep -> Maybe TypeRep
49 -- let iTy = mkTyCon "Int" in show (mkAppTy (mkTyCon ",,")
52 -- returns "(Int,Int,Int)"
54 -- The TypeRep Show instance promises to print tuple types
55 -- correctly. Tuple type constructors are specified by a
56 -- sequence of commas, e.g., (mkTyCon ",,,,,,") returns
67 IORef, newIORef, readIORef, writeIORef
74 unsafeCoerce = primUnsafeCoerce
78 unsafeCoerce :: a -> b
79 unsafeCoerce = unsafeCoerce#
83 The dynamic type is represented by Dynamic, carrying
84 the dynamic value along with its type representation:
87 -- the instance just prints the type representation.
88 instance Show Dynamic where
89 showsPrec _ (Dynamic t _) =
95 Operations for going to and from Dynamic:
98 toDyn :: Typeable a => a -> Dynamic
99 toDyn v = Dynamic (typeOf v) (unsafeCoerce v)
101 fromDyn :: Typeable a => Dynamic -> a -> a
102 fromDyn (Dynamic t v) def
103 | typeOf def == t = unsafeCoerce v
106 fromDynamic :: Typeable a => Dynamic -> Maybe a
107 fromDynamic (Dynamic t v) =
108 case unsafeCoerce v of
109 r | t == typeOf r -> Just r
110 | otherwise -> Nothing
113 (Abstract) universal datatype:
116 instance Show TypeRep where
117 showsPrec p (App tycon tys) =
119 [] -> showsPrec p tycon
120 [x] | tycon == listTc -> showChar '[' . shows x . showChar ']'
122 | isTupleTyCon tycon -> showTuple tycon xs
129 showsPrec p (Fun f a) =
131 showsPrec 9 f . showString " -> " . showsPrec 8 a
134 To make it possible to convert values with user-defined types
135 into type Dynamic, we need a systematic way of getting
136 the type representation of an arbitrary type. A type
137 class provides just the ticket,
140 class Typeable a where
141 typeOf :: a -> TypeRep
144 NOTE: The argument to the overloaded `typeOf' is only
145 used to carry type information, and Typeable instances
146 should *never* *ever* look at its value.
149 isTupleTyCon :: TyCon -> Bool
150 isTupleTyCon (TyCon _ (',':_)) = True
151 isTupleTyCon _ = False
153 instance Show TyCon where
154 showsPrec _ (TyCon _ s) = showString s
158 If we enforce the restriction that there is only one
159 @TyCon@ for a type & it is shared among all its uses,
160 we can map them onto Ints very simply. The benefit is,
161 of course, that @TyCon@s can then be compared efficiently.
163 Provided the implementor of other @Typeable@ instances
164 takes care of making all the @TyCon@s CAFs (toplevel constants),
167 If this constraint does turn out to be a sore thumb, changing
168 the Eq instance for TyCons is trivial.
171 mkTyCon :: String -> TyCon
172 mkTyCon str = unsafePerformIO $ do
178 uni = unsafePerformIO ( newIORef 0 )
181 Some (Show.TypeRep) helpers:
184 showArgs :: Show a => [a] -> ShowS
186 showArgs [a] = showsPrec 10 a
187 showArgs (a:as) = showsPrec 10 a . showString " " . showArgs as
189 showTuple :: TyCon -> [TypeRep] -> ShowS
190 showTuple (TyCon _ str) args = showChar '(' . go str args
192 go [] [a] = showsPrec 10 a . showChar ')'
193 go _ [] = showChar ')' -- a failure condition, really.
194 go (',':xs) (a:as) = showsPrec 10 a . showChar ',' . go xs as
195 go _ _ = showChar ')'
199 mkAppTy :: TyCon -> [TypeRep] -> TypeRep
200 mkAppTy tyc args = App tyc args
202 mkFunTy :: TypeRep -> TypeRep -> TypeRep
203 mkFunTy f a = Fun f a
209 -- (f::(a->b)) `dynApply` (x::a) = (f a)::b
210 dynApply :: Dynamic -> Dynamic -> Maybe Dynamic
211 dynApply (Dynamic t1 f) (Dynamic t2 x) =
212 case applyTy t1 t2 of
213 Just t3 -> Just (Dynamic t3 ((unsafeCoerce f) x))
216 dynApp :: Dynamic -> Dynamic -> Dynamic
217 dynApp f x = case dynApply f x of
219 Nothing -> error ("Type error in dynamic application.\n" ++
220 "Can't apply function " ++ show f ++
221 " to argument " ++ show x)
223 applyTy :: TypeRep -> TypeRep -> Maybe TypeRep
224 applyTy (Fun t1 t2) t3
226 applyTy _ _ = Nothing
231 instance Typeable Int where
232 typeOf _ = mkAppTy intTc []
234 instance Typeable Char where
235 typeOf _ = mkAppTy charTc []
237 instance Typeable Bool where
238 typeOf _ = mkAppTy boolTc []
240 instance Typeable Float where
241 typeOf _ = mkAppTy floatTc []
243 instance Typeable Double where
244 typeOf _ = mkAppTy doubleTc []
246 instance Typeable Integer where
247 typeOf _ = mkAppTy integerTc []
249 instance Typeable a => Typeable (IO a) where
250 typeOf action = mkAppTy ioTc [typeOf (doIO action)]
255 instance Typeable a => Typeable [a] where
256 typeOf ls = mkAppTy listTc [typeOf (hd ls)]
261 instance Typeable a => Typeable (Maybe a) where
262 typeOf mb = mkAppTy maybeTc [typeOf (getJ mb)]
267 instance (Typeable a, Typeable b) => Typeable (Either a b) where
268 typeOf ei = mkAppTy eitherTc [typeOf (getL ei), typeOf (getR ei)]
270 getL :: Either a b -> a
272 getR :: Either a b -> a
275 instance (Typeable a, Typeable b) => Typeable (a -> b) where
276 typeOf f = mkFunTy (typeOf (arg f)) (typeOf (res f))
284 instance Typeable () where
285 typeOf _ = mkAppTy unitTc []
287 instance Typeable TypeRep where
288 typeOf _ = mkAppTy typeRepTc []
290 instance Typeable TyCon where
291 typeOf _ = mkAppTy tyConTc []
293 instance Typeable Dynamic where
294 typeOf _ = mkAppTy dynamicTc []
296 instance Typeable Ordering where
297 typeOf _ = mkAppTy orderingTc []
299 instance (Typeable a, Typeable b) => Typeable (a,b) where
300 typeOf tu = mkAppTy tup2Tc [typeOf (fst tu), typeOf (snd tu)]
307 instance ( Typeable a
309 , Typeable c) => Typeable (a,b,c) where
310 typeOf tu = mkAppTy tup3Tc [ typeOf (fst tu)
322 instance ( Typeable a
325 , Typeable d) => Typeable (a,b,c,d) where
326 typeOf tu = mkAppTy tup4Tc [ typeOf (fst tu)
332 fst :: (a,b,c,d) -> a
334 snd :: (a,b,c,d) -> b
336 thd :: (a,b,c,d) -> c
338 fth :: (a,b,c,d) -> d
341 instance ( Typeable a
345 , Typeable e) => Typeable (a,b,c,d,e) where
346 typeOf tu = mkAppTy tup5Tc [ typeOf (fst tu)
353 fst :: (a,b,c,d,e) -> a
355 snd :: (a,b,c,d,e) -> b
357 thd :: (a,b,c,d,e) -> c
359 fth :: (a,b,c,d,e) -> d
361 ffth :: (a,b,c,d,e) -> e
366 @TyCon@s are provided for the following:
370 intTc, charTc, boolTc :: TyCon
371 intTc = mkTyCon "Int"
372 charTc = mkTyCon "Char"
373 boolTc = mkTyCon "Bool"
375 tup2Tc, tup3Tc, tup4Tc, tup5Tc :: TyCon
377 tup3Tc = mkTyCon ",,"
378 tup4Tc = mkTyCon ",,,"
379 tup5Tc = mkTyCon ",,,,"
381 floatTc, doubleTc, integerTc :: TyCon
382 floatTc = mkTyCon "Float"
383 doubleTc = mkTyCon "Double"
384 integerTc = mkTyCon "Integer"
386 ioTc, maybeTc, eitherTc, listTc :: TyCon
388 maybeTc = mkTyCon "Maybe"
389 eitherTc = mkTyCon "Either"
390 listTc = mkTyCon "[]"
392 unitTc, orderingTc, arrayTc, complexTc, handleTc :: TyCon
393 unitTc = mkTyCon "()"
394 orderingTc = mkTyCon "Ordering"
395 arrayTc = mkTyCon "Array"
396 complexTc = mkTyCon "Complex"
397 handleTc = mkTyCon "Handle"
399 -- Hugs/GHC extension lib types:
400 addrTc, stablePtrTc, mvarTc :: TyCon
401 addrTc = mkTyCon "Addr"
402 stablePtrTc = mkTyCon "StablePtr"
403 mvarTc = mkTyCon "MVar"
405 foreignObjTc, stTc :: TyCon
406 foreignObjTc = mkTyCon "ForeignObj"
409 int8Tc, int16Tc, int32Tc, int64Tc :: TyCon
410 int8Tc = mkTyCon "Int8"
411 int16Tc = mkTyCon "Int16"
412 int32Tc = mkTyCon "Int32"
413 int64Tc = mkTyCon "Int64"
415 word8Tc, word16Tc, word32Tc, word64Tc :: TyCon
416 word8Tc = mkTyCon "Word8"
417 word16Tc = mkTyCon "Word16"
418 word32Tc = mkTyCon "Word32"
419 word64Tc = mkTyCon "Word64"
421 tyConTc, typeRepTc, dynamicTc :: TyCon
422 tyConTc = mkTyCon "TyCon"
423 typeRepTc = mkTyCon "Type"
424 dynamicTc = mkTyCon "Dynamic"
428 byteArrayTc, mutablebyteArrayTc, wordTc :: TyCon
429 byteArrayTc = mkTyCon "ByteArray"
430 mutablebyteArrayTc = mkTyCon "MutableByteArray"
431 wordTc = mkTyCon "Word"
437 test1,test2, test3, test4 :: Dynamic
439 test1 = toDyn (1::Int)
440 test2 = toDyn ((+) :: Int -> Int -> Int)
441 test3 = dynApp test2 test1
442 test4 = dynApp test3 test1
444 test5, test6,test7 :: Int
445 test5 = fromDyn test4 0
446 test6 = fromDyn test1 0
447 test7 = fromDyn test2 0
450 test8 = toDyn (mkAppTy listTc)
453 test9 = fromDyn test8 0
455 printf :: String -> [Dynamic] -> IO ()
456 printf str args = putStr (decode str args)
459 decode ('%':'n':cs) (d:ds) =
460 (\ v -> show v++decode cs ds) (fromDyn d (0::Int))
461 decode ('%':'c':cs) (d:ds) =
462 (\ v -> show v++decode cs ds) (fromDyn d ('\0'))
463 decode ('%':'b':cs) (d:ds) =
464 (\ v -> show v++decode cs ds) (fromDyn d (False::Bool))
465 decode (x:xs) ds = x:decode xs ds
468 test10 = printf "%n = %c, that much is %b\n" [toDyn (3::Int),toDyn 'a', toDyn False]