@@ -1,8 +1,86 @@
1+-- | Runtime type representation of terms with support for rank-1 polymorphic
2+-- types with type variables of kind *.
4+-- The essence of this module is that we use the standard 'Typeable'
5+-- representation of "Data.Typeable" but we introduce a special (empty) data
6+-- type 'TypVar' which represents type variables. 'TypVar' is indexed by an
7+-- arbitrary other data type, giving you an unbounded number of type variables;
8+-- for convenience, we define 'ANY', 'ANY1', .., 'ANY9'.
10+-- [Examples of isInstanceOf]
12+-- > -- We CANNOT use a term of type 'Int -> Bool' as 'Int -> Int'
13+-- > > typeOf (undefined :: Int -> Int) `isInstanceOf` typeOf (undefined :: Int -> Bool)
14+-- > Left "Cannot unify Int and Bool"
16+-- > -- We CAN use a term of type 'forall a. a -> Int' as 'Int -> Int'
17+-- > > typeOf (undefined :: Int -> Int) `isInstanceOf` typeOf (undefined :: ANY -> Int)
20+-- > -- We CAN use a term of type 'forall a b. a -> b' as 'forall a. a -> a'
21+-- > > typeOf (undefined :: ANY -> ANY) `isInstanceOf` typeOf (undefined :: ANY -> ANY1)
24+-- > -- We CANNOT use a term of type 'forall a. a -> a' as 'forall a b. a -> b'
25+-- > > typeOf (undefined :: ANY -> ANY1) `isInstanceOf` typeOf (undefined :: ANY -> ANY)
26+-- > Left "Cannot unify Succ and Zero"
28+-- > -- We CAN use a term of type 'forall a. a' as 'forall a. a -> a'
29+-- > > typeOf (undefined :: ANY -> ANY) `isInstanceOf` typeOf (undefined :: ANY)
32+-- > -- We CANNOT use a term of type 'forall a. a -> a' as 'forall a. a'
33+-- > > typeOf (undefined :: ANY) `isInstanceOf` typeOf (undefined :: ANY -> ANY)
34+-- > Left "Cannot unify Skolem and ->"
36+-- (Admittedly, the quality of the type errors could be improved.)
38+-- [Examples of funResultTy]
40+-- > -- Apply fn of type (forall a. a -> a) to arg of type Bool gives Bool
41+-- > > funResultTy (typeOf (undefined :: ANY -> ANY)) (typeOf (undefined :: Bool))
44+-- > -- Apply fn of type (forall a b. a -> b -> a) to arg of type Bool gives forall a. a -> Bool
45+-- > > funResultTy (typeOf (undefined :: ANY -> ANY1 -> ANY)) (typeOf (undefined :: Bool))
46+-- > Right (ANY -> Bool) -- forall a. a -> Bool
48+-- > -- Apply fn of type (forall a. (Bool -> a) -> a) to argument of type (forall a. a -> a) gives Bool
49+-- > > funResultTy (typeOf (undefined :: (Bool -> ANY) -> ANY)) (typeOf (undefined :: ANY -> ANY))
52+-- > -- Apply fn of type (forall a b. a -> b -> a) to arg of type (forall a. a -> a) gives (forall a b. a -> b -> b)
53+-- > > funResultTy (typeOf (undefined :: ANY -> ANY1 -> ANY)) (typeOf (undefined :: ANY1 -> ANY1))
54+-- > Right (ANY -> ANY1 -> ANY1)
56+-- > -- Cannot apply function of type (forall a. (a -> a) -> a -> a) to arg of type (Int -> Bool)
57+-- > > funResultTy (typeOf (undefined :: (ANY -> ANY) -> (ANY -> ANY))) (typeOf (undefined :: Int -> Bool))
58+-- > Left "Cannot unify Int and Bool"
1module Data.Rank1Typeable
59module Data.Rank1Typeable
2− ( Rank1TypeRep
60+ ( -- * Basic types
3− , underlyingTypeRep
61+ TypeRep
66+ -- * Operations on type representations
5 -- * Type variables
70 -- * Type variables
@@ -13,95 +91,240 @@ module Data.Rank1Typeable
16− -- * Internal functions
94+ -- * Re-exports from Typeable
17− , occurs
95+ , Typeable
22−import Data.Typeable (Typeable, TypeRep, TyCon)
98+import Prelude hiding (succ)
23−import Control.Arrow ((***))
99+import Control.Arrow ((***), second)
100+import Control.Monad (void)
101+import Control.Applicative ((<$>))
102+import Data.List (intersperse, isPrefixOf)
103+import Data.Maybe (fromMaybe)
104+import Data.Typeable (Typeable, TyCon, tyConName, mkTyCon3)
105+import Data.Typeable.Internal (listTc, funTc)
24−import qualified Data.Typeable as Typeable (typeOf, splitTyConApp, mkTyConApp)
106+import qualified Data.Typeable as Typeable
113+--------------------------------------------------------------------------------
115+--------------------------------------------------------------------------------
117+-- | Dynamic type representation with support for rank-1 types
118+newtype TypeRep = TypeRep {
119+ -- | Return the underlying standard ("Data.Typeable") type representation
26−newtype Rank1TypeRep = Rank1TypeRep { underlyingTypeRep :: TypeRep }
120+ underlyingTypeRep :: Typeable.TypeRep
27 deriving Eq
122 deriving Eq
29−instance Show Rank1TypeRep where
124+-- | The type representation of any 'Typeable' term
30− show = show . underlyingTypeRep
32−typeOf :: Typeable a => a -> Rank1TypeRep
125+typeOf :: Typeable a => a -> TypeRep
33−typeOf = Rank1TypeRep . Typeable.typeOf
126+typeOf = TypeRep . Typeable.typeOf
35−data ANY deriving Typeable
128+--------------------------------------------------------------------------------
36−data ANY1 deriving Typeable
129+-- Constructors/destructors (views) --
37−data ANY2 deriving Typeable
130+--------------------------------------------------------------------------------
38−data ANY3 deriving Typeable
131+
39−data ANY4 deriving Typeable
132+-- | Split a type representation into the application of
40−data ANY5 deriving Typeable
133+-- a type constructor and its argument
41−data ANY6 deriving Typeable
42−data ANY7 deriving Typeable
43−data ANY8 deriving Typeable
44−data ANY9 deriving Typeable
46−tvars :: [Rank1TypeRep]
48− [ typeOf (undefined :: ANY)
49− , typeOf (undefined :: ANY1)
50− , typeOf (undefined :: ANY2)
51− , typeOf (undefined :: ANY3)
52− , typeOf (undefined :: ANY4)
53− , typeOf (undefined :: ANY5)
54− , typeOf (undefined :: ANY6)
55− , typeOf (undefined :: ANY7)
56− , typeOf (undefined :: ANY8)
57− , typeOf (undefined :: ANY9)
60−isTVar :: Rank1TypeRep -> Bool
61−isTVar = flip elem tvars
63−splitTyConApp :: Rank1TypeRep -> (TyCon, [Rank1TypeRep])
134+splitTyConApp :: TypeRep -> (TyCon, [TypeRep])
64splitTyConApp t =
135splitTyConApp t =
65 let (c, ts) = Typeable.splitTyConApp (underlyingTypeRep t)
136 let (c, ts) = Typeable.splitTyConApp (underlyingTypeRep t)
66− in (c, map Rank1TypeRep ts)
137+ in (c, map TypeRep ts)
139+-- | Inverse of 'splitTyConApp'
68−mkTyConApp :: TyCon -> [Rank1TypeRep] -> Rank1TypeRep
140+mkTyConApp :: TyCon -> [TypeRep] -> TypeRep
69mkTyConApp c ts
141mkTyConApp c ts
70− = Rank1TypeRep (Typeable.mkTyConApp c (map underlyingTypeRep ts))
142+ = TypeRep (Typeable.mkTyConApp c (map underlyingTypeRep ts))
72−occurs :: Rank1TypeRep -> Rank1TypeRep -> Bool
144+isTypVar :: TypeRep -> Maybe Var
73−occurs x t
145+isTypVar (splitTyConApp -> (c, [t])) | c == typVar = Just t
74− | x == t = True
146+isTypVar _ = Nothing
148+mkTypVar :: Var -> TypeRep
149+mkTypVar x = mkTyConApp typVar [x]
75− | otherwise = let (_, ts) = splitTyConApp t
152+typVar = let (c, _) = splitTyConApp (typeOf (undefined :: TypVar V0)) in c
76− in any (occurs x) ts
153+
78−subst :: Rank1TypeRep -> Rank1TypeRep -> Rank1TypeRep -> Rank1TypeRep
155+skolem = let (c, _) = splitTyConApp (typeOf (undefined :: Skolem V0)) in c
80− | x == t' = t
157+--------------------------------------------------------------------------------
81− | otherwise = let (c, ts) = splitTyConApp t'
158+-- Type variables --
82− in mkTyConApp c (map (subst x t) ts)
159+--------------------------------------------------------------------------------
84−unify :: Monad m => Rank1TypeRep -> Rank1TypeRep -> m [(Rank1TypeRep, Rank1TypeRep)]
161+data TypVar a deriving Typeable
162+data Skolem a deriving Typeable
163+data Zero deriving Typeable
164+data Succ a deriving Typeable
178+type ANY1 = TypVar V1
179+type ANY2 = TypVar V2
180+type ANY3 = TypVar V3
181+type ANY4 = TypVar V4
182+type ANY5 = TypVar V5
183+type ANY6 = TypVar V6
184+type ANY7 = TypVar V7
185+type ANY8 = TypVar V8
186+type ANY9 = TypVar V9
188+--------------------------------------------------------------------------------
189+-- Operations on type reps --
190+--------------------------------------------------------------------------------
192+-- | If 'isInstanceOf' fails it returns a type error
193+type TypeError = String
195+-- | @t1 `isInstanceOf` t2@ checks if @t1@ is an instance of @t2@
196+isInstanceOf :: TypeRep -> TypeRep -> Either TypeError ()
85−unify t1 t2 = unify' [(t1, t2)]
197+isInstanceOf t1 t2 = void (unify (skolemize t1) t2)
87−unify' :: Monad m
199+-- | @funResultTy t1 t2@ is the type of the result when applying a function
88− => [(Rank1TypeRep, Rank1TypeRep)]
200+-- of type @t1@ to an argument of type @t2@
89− -> m [(Rank1TypeRep, Rank1TypeRep)]
201+funResultTy :: TypeRep -> TypeRep -> Either TypeError TypeRep
90−unify' [] =
202+funResultTy (splitTyConApp -> (fc, [farg, fres])) x | fc == funTc = do
91− return []
203+ s <- unify (alphaRename "f" farg) (alphaRename "x" x)
92−unify' ((x, t) : eqs) | isTVar x && not (isTVar t) =
204+ return (normalize (subst s (alphaRename "f" fres)))
93− if x `occurs` t
205+funResultTy f _ =
94− then fail "Occurs check"
206+ Left $ show f ++ " is not a function"
208+--------------------------------------------------------------------------------
209+-- Alpha-renaming and normalization --
210+--------------------------------------------------------------------------------
212+alphaRename :: String -> TypeRep -> TypeRep
213+alphaRename prefix (isTypVar -> Just x) =
214+ mkTypVar (mkTyConApp (mkTyCon prefix) [x])
215+alphaRename prefix (splitTyConApp -> (c, ts)) =
216+ mkTyConApp c (map (alphaRename prefix) ts)
218+tvars :: TypeRep -> [Var]
219+tvars (isTypVar -> Just x) = [x]
220+tvars (splitTyConApp -> (_, ts)) = concatMap tvars ts
222+normalize :: TypeRep -> TypeRep
223+normalize t = subst (zip (tvars t) anys) t
226+ anys = map mkTypVar (iterate succ zero)
228+ succ :: TypeRep -> TypeRep
229+ succ = mkTyConApp succTyCon . (:[])
232+ zero = mkTyConApp zeroTyCon []
234+mkTyCon :: String -> TyCon
235+mkTyCon = mkTyCon3 "rank1typeable" "Data.Rank1Typeable"
238+succTyCon = let (c, _) = splitTyConApp (typeOf (undefined :: Succ Zero)) in c
241+zeroTyCon = let (c, _) = splitTyConApp (typeOf (undefined :: Zero)) in c
243+--------------------------------------------------------------------------------
245+--------------------------------------------------------------------------------
247+type Substitution = [(Var, TypeRep)]
248+type Equation = (TypeRep, TypeRep)
251+skolemize :: TypeRep -> TypeRep
252+skolemize (isTypVar -> Just x) = mkTyConApp skolem [x]
253+skolemize (splitTyConApp -> (c, ts)) = mkTyConApp c (map skolemize ts)
255+occurs :: Var -> TypeRep -> Bool
256+occurs x (isTypVar -> Just x') = x == x'
257+occurs x (splitTyConApp -> (_, ts)) = any (occurs x) ts
259+subst :: Substitution -> TypeRep -> TypeRep
260+subst s (isTypVar -> Just x) = fromMaybe (mkTypVar x) (lookup x s)
261+subst s (splitTyConApp -> (c, ts)) = mkTyConApp c (map (subst s) ts)
265+ -> Either TypeError Substitution
266+unify = \t1 t2 -> go [] [(t1, t2)]
270+ -> Either TypeError Substitution
273+ go acc ((t1, t2) : eqs) | t1 == t2 = -- Note: equality check is fast
275+ go acc ((isTypVar -> Just x, t) : eqs) =
277+ then Left "Occurs check"
278+ else go ((x, t) : map (second $ subst [(x, t)]) acc)
96− s <- unify' (map (subst x t *** subst x t) eqs)
279+ (map (subst [(x, t)] *** subst [(x, t)]) eqs)
97− return ((x, t) : s)
280+ go acc ((t, isTypVar -> Just x) : eqs) =
98−unify' ((t, x) : eqs) | isTVar x && not (isTVar t) =
281+ go acc ((mkTypVar x, t) : eqs)
99− unify' ((x, t) : eqs)
100−unify' ((x, x') : eqs) | isTVar x && isTVar x' && x == x' =
102−unify' ((t1, t2) : eqs) = do
103− let (c1, ts1) = splitTyConApp t1
282+ go acc ((splitTyConApp -> (c1, ts1), splitTyConApp -> (c2, ts2)) : eqs) =
104− (c2, ts2) = splitTyConApp t2
105− if c1 /= c2
283+ if c1 /= c2
106− then fail $ "Cannot unify' " ++ show c1 ++ " and " ++ show c2
284+ then Left $ "Cannot unify " ++ show c1 ++ " and " ++ show c2
107− else unify' (zip ts1 ts2 ++ eqs)
285+ else go acc (zip ts1 ts2 ++ eqs)
287+--------------------------------------------------------------------------------
288+-- Pretty-printing --
289+--------------------------------------------------------------------------------
291+instance Show TypeRep where
292+ showsPrec p (splitTyConApp -> (tycon, tys)) =
294+ [] -> showsPrec p tycon
295+ [anyIdx -> Just i] | tycon == typVar -> showString "ANY" . showIdx i
296+ [x] | tycon == listTc ->
297+ showChar '[' . shows x . showChar ']'
298+ [a,r] | tycon == funTc ->
299+ showParen (p > 8) $ showsPrec 9 a
302+ xs | isTupleTyCon tycon ->
305+ showParen (p > 9) $ showsPrec p tycon
309+ showIdx 0 = showString ""
312+showArgs :: Show a => [a] -> ShowS
314+showArgs [a] = showsPrec 10 a
315+showArgs (a:as) = showsPrec 10 a . showString " " . showArgs as
317+anyIdx :: TypeRep -> Maybe Int
318+anyIdx (splitTyConApp -> (c, [])) | c == zeroTyCon = Just 0
319+anyIdx (splitTyConApp -> (c, [t])) | c == succTyCon = (+1) <$> anyIdx t
322+showTuple :: [TypeRep] -> ShowS
323+showTuple args = showChar '('
324+ . foldr (.) id ( intersperse (showChar ',')
325+ $ map (showsPrec 10) args
329+isTupleTyCon :: TyCon -> Bool
330+isTupleTyCon = isPrefixOf "(," . tyConName