Haskell - 将De Bruijn术语转换为Lambda术语(反之亦然)

时间:2015-03-08 20:24:45

标签: haskell lambda

我有一个编写Haskell程序的任务,该程序能够将De Bruijn术语转换为Lambda术语,并将Lambda术语转换为De Bruijn术语,并检查术语是否“关闭”。

我不是在寻找某人为我做这项任务,但我们将非常感谢您的帮助!我对如何开始这个问题基本上一无所知。

所以,我最大的问题是:De Bruijn术语和Lambda术语之间有什么区别? 我理解变量被“关闭”意味着什么,但我怎么能在Haskell中检查它呢?

非常感谢您能想到的任何其他帮助。

以下是完整的作业:

  

(通常)lambda术语定义为数据类型:

data Term = Var Int | Lam Int Term | App Term Term deriving (Eq, Show, Read)
     

其中变量表示为整数。一个术语叫做封闭   如果i中的每个Var i都有一个来自Lam i <subterm>的术语   从它到根的路径,为它提供一个绑定。

     

De Bruijn术语被定义为数据类型:

data BTerm =BVar Int | BLam BTerm | BApp BTerm BTerm deriving (Eq,  Show, Read)
     

编写一个Haskell函数db2lam,将de Bruijn项转换为   一个lambda术语。编写一个转换a的Haskell函数lam2db   lambda术语成为Bruijn术语。

     

编写一个函数isClosed,用于测试lambda术语是否已关闭。写   函数isClosed,用于测试de Bruijn项是否已关闭。

     

选择以下两个科目之一:

     

a)为de Bruijn条款实施正常的订单beta减少   b)对(通常的)lambda术语实施正常的订单beta减少

非常感谢您的帮助(大或小)!我正处于学习Haskell的早期阶段,很抱歉这么不确定!这个任务在这个时候已经超出了我的想法。

3 个答案:

答案 0 :(得分:5)

基本上你的任务是要求你探索&#34;命名&#34;之间的区别。和#34;无名&#34; lambda calculi实现。通常,当我们作为人类编写lambda术语时,我们使用命名变量(如

)来编写它们
(\g -> (\f -> f (\x -> g x))) (\m -> m)

在假设名称是&#34;绑定&#34;的情况下工作。通过lambda然后我们可以独特地追踪在lambda体中使用该名称的所有地方。特别是像&#34;阴影&#34;等概念。变得重要。

作为一个小的切线,我们必须注意,当我们写下命名的lambda术语时,它们是非唯一的。如果我们真的很迂腐,那么我们注意到(\x -> x)(\y -> y)是不同的术语。我们知道它们最终代表相同的过程&#34;但是因此引入了 alpha-equivalence 的概念来处理两个相似的命名lambda术语实际上可能在功能上相同的事实。这是一个名为lambda术语的语句,其特点是重命名&#34;在哪里&#34;重命名&#34;按照你认为应该的方式工作。

命名为lambda术语的一个更重要的方面是&#34;通过替换&#34;捕获,这是天真实现中的一个缺陷。特别是,虽然alpha等效表明两个术语相等于重命名,但某些病态的冲突重命名可能会违反这些术语,例如

(\x -> (\q -> q x))  ====>  (\x -> (\x -> x x))

虽然重命名q -> x可能是允许的,因为我改变了q - lambda术语&#34;捕获&#34;变量导致我的程序改变的意义。这显然是病态的,但在实施替代时也很容易意外制定。

捕获 - 避免替换通常是一个重要的事情。随着LC ADT的片段移动并在其新的替代上下文中进行解释,其含义会发生变化,并且必须考虑到这种变化。也就是说,使用命名术语进行捕获避免替换可能很昂贵,因为必须知道整个术语的上下文才能识别哪些名称有被捕获的风险。

因此,出于这两个原因,尽管人性化的熟悉程度,但是对等同性的需求以及捕获命名风险的需求并不总是最佳选择。

所以现在我们转向无名的术语。 de Bruijn将您的作业要求您实施的是无名的。特别是,如果你看一下ADT,很清楚BLam s不再指定哪个变量受它们约束---我们反而强迫它确定变量的含义。仅ADT的结构。

特别是,规则是变量是绑定它们的lambda的指针。 BVar n绑定到lambda,它位于n BLam之上。因此,如果我们要将翻译从命名转换为无名的术语,那么它们看起来像

(\x -> x)            ===>  (\ 0)
(\x -> (\q -> q x))  ===>  (\ (\ 0 1))

(\g -> (\f -> f (\x -> g x))) (\m -> m)
===>
(\ (\ 0 (\ 2 0))) (\ 0)

无名的术语很难像人类一样阅读,但它们有两个很好的特质:

  1. 不再存在alpha-equivalence这样的东西;两个无名的术语在结构上相等时完全代表相同的计算
  2. 因为变量非常系统地被命名为#34;完全由于实现捕获避免这一术语的结构有点简单。

答案 1 :(得分:3)

带有De Bruijn index的变量指的是距离它很远的lambda。最简单的例子是BLam (BVar 0),它是身份函数。 (我喜欢在0 跳过 lambdas开始计数,其他作者从1 st lambda开始计数。)变量BVar 0由lambda绑定中间没有lambda。

通常的lambda术语中的变量是指具有相同名称的最接近的lambda。最简单的例子是身份函数Lam 1 (Var 1),它可以使用我们想要的任何变量名来编写; Lam 2 (Var 2)Lam 3 (Var 3),...都是相同的身份函数。通常lambda术语中的lambdas需要知道它们绑定的变量的名称。 De Bruijn索引术语中的lambdas不需要变量名,它们总是开始绑定变量BVar 0

答案 2 :(得分:2)

(所有家庭作业类型问题的通用答案)

&#34;此时这项任务已经超出了我的想法。&#34;

你确定吗?您的老师出于以下原因设置这些作业:他们与讲座有关。您有99.99%的机会可以使用您拥有的知识来完成它们。

检查您的讲义,检查讲座中提供的参考文献(即,转到图书馆)。我很确定答案是“De Bruijn术语与Lambda术语之间的区别是什么?&#34;在某处。

如果您在经过合理的努力后找不到它,请与您的同学一起检查,然后与您的助教一起检查,然后与您的老师联系。

可悲的是,SO容忍(甚至吸引)家庭作业类型的问题(以及回答它们的奖励),原因很明显(它会增加点击次数)。这有助于SO(短期内),但不是学生(从长远来看)。