我有一个编写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的早期阶段,很抱歉这么不确定!这个任务在这个时候已经超出了我的想法。
答案 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 :(得分: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(短期内),但不是学生(从长远来看)。