summaryrefslogtreecommitdiff
path: root/libraries/base/Data/Dynamic.hs
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/base/Data/Dynamic.hs')
-rw-r--r--libraries/base/Data/Dynamic.hs288
1 files changed, 288 insertions, 0 deletions
diff --git a/libraries/base/Data/Dynamic.hs b/libraries/base/Data/Dynamic.hs
new file mode 100644
index 0000000000..42313fd07c
--- /dev/null
+++ b/libraries/base/Data/Dynamic.hs
@@ -0,0 +1,288 @@
+{-# OPTIONS -fno-implicit-prelude #-}
+-----------------------------------------------------------------------------
+--
+-- Module : Data.Dynamic
+-- Copyright : (c) The University of Glasgow 2001
+-- License : BSD-style (see the file libraries/core/LICENSE)
+--
+-- Maintainer : libraries@haskell.org
+-- Stability : experimental
+-- Portability : non-portable
+--
+-- $Id: Dynamic.hs,v 1.1 2001/06/28 14:15:02 simonmar Exp $
+--
+-- The Dynamic interface provides basic support for dynamic types.
+--
+-- Operations for injecting values of arbitrary type into
+-- a dynamically typed value, Dynamic, are provided, together
+-- with operations for converting dynamic values into a concrete
+-- (monomorphic) type.
+--
+-- The Dynamic implementation provided is closely based on code
+-- contained in Hugs library of the same name.
+--
+-----------------------------------------------------------------------------
+
+module Data.Dynamic
+ (
+ -- dynamic type
+ Dynamic -- abstract, instance of: Show, Typeable
+ , toDyn -- :: Typeable a => a -> Dynamic
+ , fromDyn -- :: Typeable a => Dynamic -> a -> a
+ , fromDynamic -- :: Typeable a => Dynamic -> Maybe a
+
+ -- type representation
+
+ , Typeable(
+ typeOf) -- :: a -> TypeRep
+
+ -- Dynamic defines Typeable instances for the following
+ -- Prelude types: [a], (), (a,b), (a,b,c), (a,b,c,d),
+ -- (a,b,c,d,e), (a->b), (Array a b), Bool, Char,
+ -- (Complex a), Double, (Either a b), Float, Handle,
+ -- Int, Integer, (IO a), (Maybe a), Ordering
+
+ , TypeRep -- abstract, instance of: Eq, Show, Typeable
+ , TyCon -- abstract, instance of: Eq, Show, Typeable
+
+ -- type representation constructors/operators:
+ , mkTyCon -- :: String -> TyCon
+ , mkAppTy -- :: TyCon -> [TypeRep] -> TypeRep
+ , mkFunTy -- :: TypeRep -> TypeRep -> TypeRep
+ , applyTy -- :: TypeRep -> TypeRep -> Maybe TypeRep
+
+ --
+ -- let fTy = mkTyCon "Foo" in show (mkAppTy (mkTyCon ",,")
+ -- [fTy,fTy,fTy])
+ --
+ -- returns "(Foo,Foo,Foo)"
+ --
+ -- The TypeRep Show instance promises to print tuple types
+ -- correctly. Tuple type constructors are specified by a
+ -- sequence of commas, e.g., (mkTyCon ",,,,") returns
+ -- the 5-tuple tycon.
+ ) where
+
+
+#ifdef __GLASGOW_HASKELL__
+import GHC.Base
+import GHC.Maybe
+import GHC.Show
+import GHC.Err
+import GHC.Num
+import GHC.Float
+import GHC.IOBase
+import GHC.Dynamic
+#endif
+
+#ifdef __GLASGOW_HASKELL__
+import GHC.Prim ( unsafeCoerce# )
+
+unsafeCoerce :: a -> b
+unsafeCoerce = unsafeCoerce#
+#endif
+
+#include "Dynamic.h"
+
+-- The dynamic type is represented by Dynamic, carrying
+-- the dynamic value along with its type representation:
+
+-- the instance just prints the type representation.
+instance Show Dynamic where
+ showsPrec _ (Dynamic t _) =
+ showString "<<" .
+ showsPrec 0 t .
+ showString ">>"
+
+-- Operations for going to and from Dynamic:
+
+toDyn :: Typeable a => a -> Dynamic
+toDyn v = Dynamic (typeOf v) (unsafeCoerce v)
+
+fromDyn :: Typeable a => Dynamic -> a -> a
+fromDyn (Dynamic t v) def
+ | typeOf def == t = unsafeCoerce v
+ | otherwise = def
+
+fromDynamic :: Typeable a => Dynamic -> Maybe a
+fromDynamic (Dynamic t v) =
+ case unsafeCoerce v of
+ r | t == typeOf r -> Just r
+ | otherwise -> Nothing
+
+-- (Abstract) universal datatype:
+
+instance Show TypeRep where
+ showsPrec p (App tycon tys) =
+ case tys of
+ [] -> showsPrec p tycon
+ [x] | tycon == listTc -> showChar '[' . shows x . showChar ']'
+ xs
+ | isTupleTyCon tycon -> showTuple tycon xs
+ | otherwise ->
+ showParen (p > 9) $
+ showsPrec p tycon .
+ showChar ' ' .
+ showArgs tys
+
+ showsPrec p (Fun f a) =
+ showParen (p > 8) $
+ showsPrec 9 f . showString " -> " . showsPrec 8 a
+
+-- To make it possible to convert values with user-defined types
+-- into type Dynamic, we need a systematic way of getting
+-- the type representation of an arbitrary type. A type
+-- class provides just the ticket,
+
+class Typeable a where
+ typeOf :: a -> TypeRep
+
+-- NOTE: The argument to the overloaded `typeOf' is only
+-- used to carry type information, and Typeable instances
+-- should *never* *ever* look at its value.
+
+isTupleTyCon :: TyCon -> Bool
+isTupleTyCon (TyCon _ (',':_)) = True
+isTupleTyCon _ = False
+
+instance Show TyCon where
+ showsPrec _ (TyCon _ s) = showString s
+
+-- If we enforce the restriction that there is only one
+-- @TyCon@ for a type & it is shared among all its uses,
+-- we can map them onto Ints very simply. The benefit is,
+-- of course, that @TyCon@s can then be compared efficiently.
+
+-- Provided the implementor of other @Typeable@ instances
+-- takes care of making all the @TyCon@s CAFs (toplevel constants),
+-- this will work.
+
+-- If this constraint does turn out to be a sore thumb, changing
+-- the Eq instance for TyCons is trivial.
+
+mkTyCon :: String -> TyCon
+mkTyCon str = unsafePerformIO $ do
+ v <- readIORef uni
+ writeIORef uni (v+1)
+ return (TyCon v str)
+
+{-# NOINLINE uni #-}
+uni :: IORef Int
+uni = unsafePerformIO ( newIORef 0 )
+
+-- Some (Show.TypeRep) helpers:
+
+showArgs :: Show a => [a] -> ShowS
+showArgs [] = id
+showArgs [a] = showsPrec 10 a
+showArgs (a:as) = showsPrec 10 a . showString " " . showArgs as
+
+showTuple :: TyCon -> [TypeRep] -> ShowS
+showTuple (TyCon _ str) args = showChar '(' . go str args
+ where
+ go [] [a] = showsPrec 10 a . showChar ')'
+ go _ [] = showChar ')' -- a failure condition, really.
+ go (',':xs) (a:as) = showsPrec 10 a . showChar ',' . go xs as
+ go _ _ = showChar ')'
+
+
+mkAppTy :: TyCon -> [TypeRep] -> TypeRep
+mkAppTy tyc args = App tyc args
+
+mkFunTy :: TypeRep -> TypeRep -> TypeRep
+mkFunTy f a = Fun f a
+
+-- Auxillary functions
+
+-- (f::(a->b)) `dynApply` (x::a) = (f a)::b
+dynApply :: Dynamic -> Dynamic -> Maybe Dynamic
+dynApply (Dynamic t1 f) (Dynamic t2 x) =
+ case applyTy t1 t2 of
+ Just t3 -> Just (Dynamic t3 ((unsafeCoerce f) x))
+ Nothing -> Nothing
+
+dynApp :: Dynamic -> Dynamic -> Dynamic
+dynApp f x = case dynApply f x of
+ Just r -> r
+ Nothing -> error ("Type error in dynamic application.\n" ++
+ "Can't apply function " ++ show f ++
+ " to argument " ++ show x)
+
+applyTy :: TypeRep -> TypeRep -> Maybe TypeRep
+applyTy (Fun t1 t2) t3
+ | t1 == t3 = Just t2
+applyTy _ _ = Nothing
+
+-- Prelude types
+
+listTc :: TyCon
+listTc = mkTyCon "[]"
+
+instance Typeable a => Typeable [a] where
+ typeOf ls = mkAppTy listTc [typeOf ((undefined:: [a] -> a) ls)]
+
+unitTc :: TyCon
+unitTc = mkTyCon "()"
+
+instance Typeable () where
+ typeOf _ = mkAppTy unitTc []
+
+tup2Tc :: TyCon
+tup2Tc = mkTyCon ","
+
+instance (Typeable a, Typeable b) => Typeable (a,b) where
+ typeOf tu = mkAppTy tup2Tc [typeOf ((undefined :: (a,b) -> a) tu),
+ typeOf ((undefined :: (a,b) -> b) tu)]
+
+tup3Tc :: TyCon
+tup3Tc = mkTyCon ",,"
+
+instance ( Typeable a , Typeable b , Typeable c) => Typeable (a,b,c) where
+ typeOf tu = mkAppTy tup3Tc [typeOf ((undefined :: (a,b,c) -> a) tu),
+ typeOf ((undefined :: (a,b,c) -> b) tu),
+ typeOf ((undefined :: (a,b,c) -> c) tu)]
+
+tup4Tc :: TyCon
+tup4Tc = mkTyCon ",,,"
+
+instance ( Typeable a
+ , Typeable b
+ , Typeable c
+ , Typeable d) => Typeable (a,b,c,d) where
+ typeOf tu = mkAppTy tup4Tc [typeOf ((undefined :: (a,b,c,d) -> a) tu),
+ typeOf ((undefined :: (a,b,c,d) -> b) tu),
+ typeOf ((undefined :: (a,b,c,d) -> c) tu),
+ typeOf ((undefined :: (a,b,c,d) -> d) tu)]
+
+tup5Tc :: TyCon
+tup5Tc = mkTyCon ",,,,"
+
+instance ( Typeable a
+ , Typeable b
+ , Typeable c
+ , Typeable d
+ , Typeable e) => Typeable (a,b,c,d,e) where
+ typeOf tu = mkAppTy tup5Tc [typeOf ((undefined :: (a,b,c,d,e) -> a) tu),
+ typeOf ((undefined :: (a,b,c,d,e) -> b) tu),
+ typeOf ((undefined :: (a,b,c,d,e) -> c) tu),
+ typeOf ((undefined :: (a,b,c,d,e) -> d) tu),
+ typeOf ((undefined :: (a,b,c,d,e) -> e) tu)]
+
+instance (Typeable a, Typeable b) => Typeable (a -> b) where
+ typeOf f = mkFunTy (typeOf ((undefined :: (a -> b) -> a) f))
+ (typeOf ((undefined :: (a -> b) -> b) f))
+
+INSTANCE_TYPEABLE0(Bool,boolTc,"Bool")
+INSTANCE_TYPEABLE0(Char,charTc,"Char")
+INSTANCE_TYPEABLE0(Float,floatTc,"Float")
+INSTANCE_TYPEABLE0(Double,doubleTc,"Double")
+INSTANCE_TYPEABLE0(Int,intTc,"Int")
+INSTANCE_TYPEABLE0(Integer,integerTc,"Integer")
+INSTANCE_TYPEABLE2(Either,eitherTc,"Either")
+INSTANCE_TYPEABLE1(IO,ioTc,"IO")
+INSTANCE_TYPEABLE1(Maybe,maybeTc,"Maybe")
+INSTANCE_TYPEABLE0(Ordering,orderingTc,"Ordering")
+
+INSTANCE_TYPEABLE0(TyCon,tyconTc,"TyCon")
+INSTANCE_TYPEABLE0(TypeRep,typeRepTc,"TypeRep")
+INSTANCE_TYPEABLE0(Dynamic,dynamicTc,"Dynamic")