LETREC作为编程语言功能的优点是什么?



我已经查看了有关LETREC的所有内容,但我仍然不明白它将语言作为功能带来的内容。LeTrec表达的所有内容似乎都可以很容易地作为递归功能写成。但是,如果该语言已经支持递归功能,是否有任何理由将公开 LETREC作为编程语言的功能?为什么几种语言都可以公开?

我知道,LETREC可能被用来实现包括递归功能在内的其他功能,但这与为什么它本身应该成为功能无关。我还读到,有些人在某些LISP中发现它比递归功能更可读,但是这又不重要,因为该语言的设计师可以努力使递归功能足够可读以不需要其他功能。最后,有人告诉我,莱特雷克(Letrec)可以更简洁地表达某些递归价值,但是我尚未找到一个激励的榜样。

tl; dr: define is letrec。这就是使我们能够首先写递归的定义的原因。

考虑

let fact = fun (n => (n==0 -> 1 ; n * fact (n-1)))

该名称fact在此定义顿的主体内部指的是什么实体?使用let foo = valval是根据已知的实体定义的,因此它不能指 foo, CC_6 ar s 尚未定义。就范围而言,这可以说(通常是)let方程的RHS在 ofter 范围中定义。

内部fact实际指向所定义的唯一方法是使用letrec,其中允许定义的实体参考定义的范围。因此,尽管在实体进行定义时对实体进行评估是错误的,但将A 参考存储到其(未来,此时)值是可以的 - 在使用letrec的情况下是。

您指的是define,只是另一个名称中的letrec。也在方案中。

没有被定义为指称自己的实体的能力,即具有非恢复let的语言,具有递归的能力,必须诉诸于使用Y-Combinator等奥术设备的使用。这很麻烦,通常效率低下。另一种方法是

之类的定义
let fact = (fun (f => f f)) (fun (r => n => (n==0 -> 1 ; n * r r (n-1))))

因此,letrec将实施效率带到了表格,并为程序员提供便利。

QUESION然后变成,为什么要暴露 non -Recursive let?哈斯克尔确实没有。方案具有letreclet。原因之一可能是为了完整。另一个可能是let的更简单的实现,在内存中,自我指指的运行时结构较少,使其更容易在垃圾收集器上。

您要求一个激励人心的例子。考虑将斐波那契数定义为一个自指的懒惰列表:

letrec fibs = {0} + {1} + add fibs (tail fibs) 

将定义列表fibs的另一个副本,将用作元素添加函数add的输入。这将导致的定义 fibs的另一个副本,以用术语定义该副本。等等;访问 n th fibonacci编号将导致在运行时创建和维护 n-1 列表的链!不是一张漂亮的图片。

也假设fibs也用于tail fibs。如果没有,所有赌注都关闭了。

需要的是 fibs使用本身,是指本身,因此仅维护列表的一个副本。

nb:尽管这不是方案特定的问题,但我正在使用方案来证明差异。希望您可以阅读一些LISP代码

a letrec只是一个特殊的 let,在评估表示其值的表达式之前定义绑定本身。想象一下:

(define (fib n)
  (let ((fib (lambda (n a b) 
               (if (zero? n) 
                   a 
                   (fib (- n 1) b (+ a b))))))
    (fib n))

此代码失败,因为虽然fib确实存在于let的主体中,但它确实存在于其定义的闭合中,因为在评估Lambda时不存在绑定。要解决此letrec进行救援:

(define (fib n)
  (letrec ((fib (lambda (n a b) 
                  (if (zero? n) 
                      a 
                      (fib (- n 1) b (+ a b))))))
    (fib n))

letrec只是这样做的语法:

(define (fib n)
  (let ((fib 'undefined))
    (let ((tmp (lambda (n a b) 
                 (if (zero? n) 
                     a 
                     (fib (- n 1) b (+ a b))))))
      (set! fib tmp))
    (fib n)))

因此,在这里评估Lambda时,您可以清楚地看到fib存在,然后将绑定设置为闭合本身。绑定是相同的,只有它的指针已经改变。它是圆形参考101 ..

那么,当您创建全局功能时会发生什么?显然,如果要重复出现,则需要在评估兰伯达或必须突变环境之前存在。它也需要在这里解决相同的问题。

在功能性语言实现中,突变不正确,您可以使用y(或z)组合器解决此问题。

如果您对如何实现语言感兴趣,我建议您从Matt Mights文章开始。

最新更新