说我有以下GADT AST:
data O a b c where
Add :: O a a a
Eq :: O a b Bool
--... more operations
data Tree a where
N :: (O a b c) -> Tree a -> Tree b -> Tree c
L :: a -> Tree a
现在我想构建一个函数来替换Tree中类型为L
的所有a
(eave),如下所示:
f :: a -> Tree b -> Tree b
f x (L a) | typeof x == typeof a = L x
f x (L a) = L a
f x (N o a b) = N o (f x a) (f x b)
是否可以构建这样的功能? (可能使用课程?) 如果对GADT进行了更改,可以这样做吗?
我已经在类中使用了typeof函数:typeof :: a -> Type
。
答案 0 :(得分:2)
我不认为使用当前的GADT是可能的,除非您可以使用部分定义的函数。你可以写
--f :: (Typeable a, Typeable b) => a -> Tree b -> Tree a
f x (L a)
| show (typeOf x) == show (typeOf a) = L x
但你不能完全使用这个功能,因为你需要
| otherwise = L a
并且不会出现类型问题,因为您刚刚证明L a :: Tree a
和L x :: Tree x
是不同的类型。
但是,如果将GADT
定义为存在量化
data Tree where
N :: (O a b c) -> Tree -> Tree -> Tree
L :: Typeable a => a -> Tree
f :: Typeable a => a -> Tree -> Tree
f x (L a)
| show (typeOf x) == show (typeOf a) = L x
| otherwise = L a
你丢失了Tree
中的类型信息,但是这个类型检查是完全的
另一个保留类型信息的版本
data Tree a b c where
N :: (O a b c) -> Tree a b c -> Tree a b c -> Tree a b c
L :: Typeable a => a -> Tree a b c
f :: Typeable a => a -> Tree a b c -> Tree a b c
f x (L a)
| show (typeOf x) == show (typeOf a) = L x
| otherwise = L a
此处,您可以保存L
类型Tree
中存储的任何可能值的类型信息。如果您只需要几种不同的类型,这可能会有效,但会很快变得笨重。
答案 1 :(得分:0)
诀窍是使用类型证人:http://www.haskell.org/haskellwiki/Type_witness
data O a b c where
Add :: O a a a
Eq :: O a b Bool
instance Show (O a b c) where
show Add = "Add"
show Eq = "Eq"
data Tree a where
T :: (Typeable a, Typeable b, Typeable c) => (O a b c) -> Tree a -> Tree b -> Tree c
L :: a -> Tree a
instance (Show a) => Show (Tree a) where
show (T o a b) = "(" ++ (show o) ++ " " ++ (show a) ++ " " ++ (show b) ++ ")"
show (L a) = (show a)
class (Show a) => Typeable a where
witness :: a -> Witness a
instance Typeable Int where
witness _ = IntWitness
instance Typeable Bool where
witness _ = BoolWitness
data Witness a where
IntWitness :: Witness Int
BoolWitness :: Witness Bool
dynamicCast :: Witness a -> Witness b -> a -> Maybe b
dynamicCast IntWitness IntWitness a = Just a
dynamicCast BoolWitness BoolWitness a = Just a
dynamicCast _ _ _ = Nothing
replace :: (Typeable a, Typeable b) => a -> b -> b
replace a b = case dynamicCast (witness a) (witness b) a of
Just v -> v
Nothing -> b
f :: (Typeable a, Typeable b) => b -> Tree a -> Tree a
f x (L a) = L $ replace x a
f x (T o a b) = T o (f x a) (f x b)