给出一种简单的语言,比如说
data E where
ValE :: Typeable a => a -> E
AppE :: E -> E -> E
然后可以将其转换为类型化表示:
data T a where
ValT :: Typeable a => a -> T a
AppT :: T (a -> b) -> T a -> T b
deriving Typeable
我尝试了各种方法,例如以下内容:
e2t :: Typeable a => E -> Maybe (T a)
e2t (ValE x) = cast (ValT x)
e2t (AppE e1 e2) = liftM2 AppT (e2t e1) (e2t e2)
这不起作用,我收到以下错误消息:
约束中的模糊类型变量'a':
'Typeable a'
因使用“e2t”而产生的......
可能的修复:添加修复这些类型变量的类型签名
但是,如果我喜欢这个
e2t :: Typeable a => E -> Maybe (T a)
e2t (ValE x) = cast (ValT x)
e2t (AppE e1 e2) = liftM2 AppT (e2t e1) (e2t e2 :: Maybe (T Int))
它编译。</ p>
答案 0 :(得分:2)
没错。您可能没有意识到,但您正在尝试对您的语言进行类型推断。如果要将表达式f x
转换为键入的GADT,仅仅知道结果类型是不够的。我们可以f :: Bool -> Int
与x :: Bool
,f :: (Int -> Int) -> Int
与x :: Int -> Int
等等。您的类型化代表声称知道这一点,特别是因为它需要Typeable
的常量(如果你没有Typeable
约束,你可能会因为知道它是什么类型而撒谎。
e2t
需要知道表达式的类型。您需要某种方法来确定应用程序的参数应该是什么类型。也许你可以通过说一些不同的东西来解决这个问题,即:
e2t :: E -> Maybe (exists a. T a)
也就是说,你只是想看看E
是否可以被赋予类型,但它告诉你,而不是告诉它应该是什么类型。这是自下而上的推理,通常更容易。对此进行编码:
data AnyT where
AnyT :: Typeable a => T a -> AnyT
嗯,在玩了一段时间之后,我意识到你在回来的路上遇到了完全相同的问题。我认为仅使用Data.Typeable
可以做到这一点。您需要从dynApp
重新创建Data.Dynamic
之类的内容,但需要T
而不是常规的Haskell类型。即你必须在TypeRep
上进行一些操作,然后在你知道它是安全的时候插入一个“只相信我”unsafeCoerce
。但据我所知,你无法说服编译器它是安全的。
这可以在Agda中完成,因为TypeRep
上的等效表示操作对于编译器是可观察的。学习这门语言可能是一个很好的练习。