我正在实现一种简单的依赖类型语言,类似于described by Lennart Augustsson,同时也使用bound来管理绑定。
当检查一个相关的lambda术语时,例如λt:* . λx:t . x
,我需要:
t
实例化为某事 λx:t . x
,屈服于∀x:t . t
t
,屈服于∀t:* . ∀x:t . t
如果lambda是非依赖的,我可以在步骤1中使用 type 实例化t
,因为类型是我需要知道的关于变量的类型第2步。
但是在第3步,我缺乏决定抽象的变量的信息。
我可以引入新的名称供应并使用包含类型和唯一名称的t
来实例化Bound.Name.Name
。但我认为bound
我不需要生成新的名字。
我是否有其他解决方案?
答案 0 :(得分:8)
我们需要某种上下文来跟踪lambda参数。但是,我们不一定需要实例化它们,因为bound
给出了de Bruijn索引,我们可以使用这些索引来索引上下文。
实际上,使用索引有点涉及,因为类型级机制通过{{1}的嵌套反映当前范围的大小(或者换句话说,表达式中的当前深度) } -s。它需要使用多态递归或GADT。它还阻止我们将状态存储在状态monad中(因为大小因此上下文的类型随着我们的递归而改变)。我想知道我们是否可以使用索引状态monad;这将是一个有趣的实验。但我离题了。
最简单的解决方案是将上下文表示为函数:
Var
type TC a = Either String a -- our checker monad
type Cxt a = a -> TC (Type a) -- the context
输入本质上是de Bruijn索引,我们通过将函数应用于索引来查找类型。我们可以通过以下方式定义空上下文:
a
我们可以扩展上下文:
emptyCxt :: Cxt a
emptyCxt = const $ Left "variable not in scope"
上下文的大小在consCxt :: Type a -> Cxt a -> Cxt (Var () a)
consCxt ty cxt (B ()) = pure (F <$> ty)
consCxt ty cxt (F a) = (F <$>) <$> cxt a
嵌套中编码。在返回类型中,尺寸的增加是显而易见的。
现在我们可以编写类型检查器了。这里的要点是我们使用Var
和fromScope
来获取绑定器,并且我们带有适当扩展的toScope
(其类型排列完全正确)。
Cxt
以上是the working code containing上述定义。我希望我没有把它弄得太糟糕。