我一直在type arithmetic上阅读Haskell wiki中的页面,并且在类型系统中嵌入lambda演算的部分遇到了一些麻烦。从那一节开始,我收集到以下代码不适用于GHC / GHCi - 显然GHC不应该能够确定g的类型签名。
{-# OPTIONS -fglasgow-exts #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
data X
data App t u
data Lam t
class Subst s t u | s t -> u
instance Subst X u u
instance (Subst s u s', Subst t u t') => Subst (App s t) u (App s' t')
instance Subst (Lam t) u (Lam t)
class Apply s t u | s t -> u
instance (Subst s t u, Eval u u') => Apply (Lam s) t u'
class Eval t u | t -> u
instance Eval X X
instance Eval (Lam t) (Lam t)
instance (Eval s s', Apply s' t u) => Eval (App s t) u
f :: Eval (App (Lam X) X) u => u
f = undefined
g :: Eval (App (Lam (App X X )) (Lam (App X X ))) u => u
g = undefined
请注意,我必须添加FlexibleContexts和UndecidableInstances,因为如果没有这些扩展,给定的代码似乎没有编译。但是,当我使用GHCi(版本8.0.2)运行时,我得到以下结果:
*Main> :t f
f :: X
*Main> :t g
g :: u
这对我来说特别奇怪,因为类型u没有在任何地方定义。这是上面两个语言扩展相互交互和glasgow-exts的结果吗?如果是这样,怎么样?
答案 0 :(得分:5)
类型where_exp
只是一个孤独的变量 - 就像u
中的a
一样。
要真正将其归结为其基本要素,请考虑以下备用文件:
undefined :: a
如果您在ghci中询问{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FlexibleInstances #-}
class Loopy a
instance Loopy a => Loopy a
x :: Loopy a => a
x = undefined
的类型,它会告诉您它的类型为x
,没有上下文。这看起来有点神奇;你只需要意识到GHC中的实例解析完全被允许递归,并且实现很大程度上支持这一点。
如果您愿意,我们可以详细介绍您的示例中发生的情况,但它与上述文件非常类似。以下是详细信息。
所以,我们想看看是否允许我们拥有这个实例:
a
我们知道
Eval (App (Lam (App X X)) (Lam (App X X))) u
因此,只要我们同时拥有这两项内容,我们就可以拥有它:
instance (Eval s s', Apply s' t u) => Eval (App s t) u
第一个很容易,因为:
Eval (Lam (App X X)) s'
Apply s' (Lam (App X X)) u
所以当我们拥有时,我们可以获得蛋糕:
instance Eval (Lam t) (Lam t)
由于
Apply (Lam (App X X)) (Lam (App X X)) u
找到我们的蛋糕,我们应该检查下这两块石头:
instance (Subst s t u, Eval u u') => Apply (Lam s) t u'
这
Subst (App X X) (Lam (App X X)) u
Eval u u'
我们知道我们可以有蛋糕了
instance (Subst s u s', Subst t u t') => Subst (App s t) u (App s' t')
这很容易取得进展,因为:
Subst X (Lam (App X X)) s'
Subst X (Lam (App X X)) t'
Eval (App s' t') u'
因此,我们可以随时拥有原始实例:
instance Subst X u u
但是,嘿,presto!这是我们正在寻找的原始实例。总而言之,只要我们拥有原始实例,我们就可以拥有原始实例。所以我们声明我们可以拥有原始实例,然后我们可以拥有原始实例!不是那个桃子。