[Haskell-cafe] typeOf for polymorphic value

oleg at okmij.org oleg at okmij.org
Thu Mar 26 01:33:05 EDT 2009


> Does anyone know of a trick to accomplish `typeOf id'?
> Using something else than TypeRep as the representation, of course.

Yes. The analysis of polymorphic types has been used in the inverse
type-checker
	http://okmij.org/ftp/Haskell/types.html#de-typechecker

The enclosed code computes TypeRep of polymorphic values. 
The code returns real TypeRep. Here are a few examples:

tt2 = mytypof not
-- Bool -> Bool

tt3 = mytypof [True]
-- [Bool]

tt4 = mytypof id
-- any1 -> any1

tt5 = mytypof []
-- [any1]

tt6 = mytypof const
-- any1 -> any2 -> any1

tt7 = mytypof Just
-- any1 -> Maybe any1

tt8 = mytypof map
-- (any1 -> any2) -> [any1] -> [any2]

tt9 = mytypof maybe
-- any1 -> (any2 -> any1) -> Maybe any2 -> any1

The code was tested on GHC 6.8.2. I don't have access to any computer
with GHC 6.10, so I can't say how it works with that version of GHC.

{-# LANGUAGE ScopedTypeVariables, EmptyDataDecls #-}
{-# LANGUAGE FlexibleInstances, FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverlappingInstances #-}
{-# LANGUAGE IncoherentInstances #-}

module Typeof where

import Data.Typeable

-- tests

tt1 = mytypof True
-- Bool

tt2 = mytypof not
-- Bool -> Bool

tt3 = mytypof [True]
-- [Bool]

tt4 = mytypof id
-- any1 -> any1

tt5 = mytypof []
-- [any1]

tt6 = mytypof const
-- any1 -> any2 -> any1

tt7 = mytypof Just
-- any1 -> Maybe any1

tt8 = mytypof map
-- (any1 -> any2) -> [any1] -> [any2]

tt9 = mytypof maybe
-- any1 -> (any2 -> any1) -> Maybe any2 -> any1

class MyTypeable a where
    mytypof :: a -> TypeRep

-- Gamma is the sequence of type varaibles. It is used to assign
-- different indices to different type variables
instance (Analyze a result, MyTypeable' HNil gout result)
    => MyTypeable a 
 where
 mytypof a = fst $ mytypof' HNil (analyze a)

class MyTypeable' gin gout classification | gin classification -> gout where
    mytypof' :: gin -> classification -> (TypeRep,gout)


instance Typeable a => MyTypeable' gin gin (TAtomic a) where
    mytypof' gin _ = (typeOf (undefined::a), gin)

instance Typeable a => MyTypeable' gin gin (TAtomic1 a) where
    mytypof' gin _ = (typeOf (undefined::a), gin)

instance (MyTypeable' gin g a, MyTypeable' g gout b)
    => MyTypeable' gin gout (TFunction a b) where
    mytypof' gin _ = let (tr1,g)    = mytypof' gin (undefined::a)
                         (tr2,gout) = mytypof' g (undefined::b)
                     in (mkFunTy tr1 tr2,gout)

instance (MyTypeable' gin g c, MyTypeable' g gout a)
    => MyTypeable' gin gout (TConstructed c a) where
    mytypof' gin _ = let (tr1,g)    = mytypof' gin (undefined::c)
                         (tr2,gout) = mytypof' g (undefined::a)
                     in (mkTyConApp (typeRepTyCon tr1) [tr2],gout)

instance (HIndex a gin n, MyTypeable'' n gin gout (TVariable a))
          => MyTypeable' gin gout (TVariable a) where
    mytypof' = mytypof'' (undefined::n)


class MyTypeable'' n gin gout classification | n gin classification ->gout where
    mytypof'' :: n -> gin -> classification -> (TypeRep,gout)


instance HLen gin n1 => MyTypeable'' Z gin (HCons a gin) (TVariable a) where
    mytypof'' _ gin _ = (mkany (undefined::S n1),
                         HCons (undefined::a) gin)

instance Nat n => MyTypeable'' (S n) gin gin (TVariable a) where
    mytypof'' _ gin _ = (mkany (undefined::S n), gin)


mkany :: Nat n => n -> TypeRep
mkany n = mkTyConApp (mkTyCon ts) []
 where
 ts = "any" ++ show (nat n)


-- Lookup the index of an item x in the list l
-- The index is 1-based. If not found, return 0
class Nat n => HIndex x l n | x l -> n

instance HIndex x HNil Z

instance (Nat n, TypeEq x a f, HIndex' f x (HCons a l) n)
    => HIndex x (HCons a l) n

class HIndex' f x l n | f x l -> n

instance HLen l n => HIndex' HTrue x l n
instance HIndex x l n => HIndex' HFalse x (HCons a l) n

-- Length of a list
class Nat n => HLen l n | l -> n
instance HLen HNil Z
instance HLen l n => HLen (HCons a l) (S n)



-- Analyze a type

-- Result of the type analysis
data TAtomic a
data TVariable a
data TFunction a b
data TConstructed c  a 

-- only one level: kind * -> *
data TAtomic1 a
data TVariable1 a

data Level1 a

data W a = W a

-- We can have more levels, cf Typeable2, etc.

class Analyze a b | a -> b
analyze:: Analyze a b => a -> b
analyze = undefined

instance TypeCast f (TAtomic Int)  => Analyze Int f
instance TypeCast f (TAtomic Bool) => Analyze Bool f
instance TypeCast f (TAtomic Char) => Analyze Char f

instance TypeCast f (TAtomic Int)  => Analyze (W Int) f
instance TypeCast f (TAtomic Bool) => Analyze (W Bool) f
instance TypeCast f (TAtomic Char) => Analyze (W Char) f

instance (Analyze (c x) rx, Analyze (d y) ry, TypeCast f (TFunction rx ry)) 
    => Analyze (c x->d y) f

instance (Analyze (W x) rx, Analyze (d y) ry, TypeCast f (TFunction rx ry)) 
    => Analyze (x->d y) f

instance (Analyze (c x) rx, Analyze (W y) ry, TypeCast f (TFunction rx ry)) 
    => Analyze (c x->y) f

instance (Analyze (W x) rx, Analyze (W y) ry, TypeCast f (TFunction rx ry)) 
    => Analyze (x->y) f

instance (Analyze (W x) rx, Analyze (W y) ry, TypeCast f (TFunction rx ry)) 
    => Analyze (W (x->y)) f


instance (Analyze (Level1 (c ())) rc, Analyze (W x) rx,
          TypeCast f (TConstructed rc rx)) 
    => Analyze (c x) f


instance TypeCast f (TAtomic1 ([] ()))    => Analyze (Level1 ([] ())) f
instance TypeCast f (TAtomic1 (Maybe ())) => Analyze (Level1 (Maybe ())) f
instance TypeCast f (TVariable1 (c ()))   => Analyze (Level1 (c ())) f


-- the most general instance
instance TypeCast f (TVariable a) => Analyze (W a) f

-- instance TypeCast f (TVariable a) => Analyze a f -- the most general instance


{-
ta1 = analyze True
-- ta1 :: TAtomic Bool

ta2 = analyze not
-- ta2 :: TFunction (TAtomic Bool) (TAtomic Bool)

ta3 = analyze [True]
-- ta3 :: TConstructed (TAtomic1 [()]) (TAtomic Bool)

ta4 = analyze id
-- ta4 :: TFunction (TVariable GHC.Prim.Any) (TVariable GHC.Prim.Any)

ta5 = analyze []
-- ta5 :: TConstructed (TAtomic1 [()]) (TVariable GHC.Prim.Any)

ta6 = analyze const
-- ta6 :: TFunction
--          (TVariable GHC.Prim.Any)
--          (TFunction (TVariable GHC.Prim.Any) (TVariable GHC.Prim.Any))

-}


-- Standard HList stuff

data Z
data S a

class Nat a where nat :: a -> Int
instance Nat Z where nat _ = 0
instance Nat a => Nat (S a) where nat _ = succ (nat (undefined::a))


data HTrue 
data HFalse 
instance Show HTrue  where show _ = "HTrue"
instance Show HFalse where show _ = "HFalse"

data HNil = HNil deriving Show
data HCons a b = HCons a b deriving Show

-- literally lifted from the HList library
class TypeCast   a b   | a -> b, b->a   where typeCast   :: a -> b
class TypeCast'  t a b | t a -> b, t b -> a where typeCast'  :: t->a->b
class TypeCast'' t a b | t a -> b, t b -> a where typeCast'' :: t->a->b
instance TypeCast'  () a b => TypeCast a b where typeCast x = typeCast' () x
instance TypeCast'' t a b => TypeCast' t a b where typeCast' = typeCast''
instance TypeCast'' () a a where typeCast'' _ x  = x

class TypeEq' () x y b => TypeEq x y b | x y -> b
    where type'eq :: x -> y -> b
          type'eq _ _ = undefined::b
class TypeEq' q x y b | q x y -> b
class TypeEq'' q x y b | q x y -> b
instance TypeEq' () x y b => TypeEq x y b
instance TypeCast b HTrue => TypeEq' () x x b
instance TypeEq'' q x y b => TypeEq' q x y b
instance TypeEq'' () x y HFalse



More information about the Haskell-Cafe mailing list