首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >方案/球拍中letrec的含义

方案/球拍中letrec的含义
EN

Stack Overflow用户
提问于 2018-05-31 23:26:51
回答 2查看 5.5K关注 0票数 8

据我所知,以下是letlet*letrecletrec*是在方案/球拍中使用的合成糖。

现在,如果我有一个简单的程序:

代码语言:javascript
复制
(let ((x 1)
      (y 2))
     (+ x y))

它被翻译成:

代码语言:javascript
复制
((lambda (x y) (+ x y)) 1 2)

如果我有:

代码语言:javascript
复制
(let* ((x 1)
      (y 2))
     (+ x y))

它被翻译成:

代码语言:javascript
复制
((lambda (x) ((lambda (y) (+ x y))) 2) 1)

现在,对于我的第一个问题,我理解了letrec表达式的含义,它使人能够在let中使用递归,但我不知道它到底是如何实现的。letrec被翻译成什么?

例如,什么将

代码语言:javascript
复制
(letrec ((x 1)
      (y 2))
     (+ x y)) 

被翻译成?

第二个问题与letrec*类似--但对于letrec*,我不明白它与letrec到底有什么不同?另外,letrec*表达式将被转换成什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-31 23:55:35

参见Oscar Waddell,Dipanwita Sarkar和R.Kent Dybvig的论文"Fixing Letrec: A Faithful Efficient Implementation of Scheme‘s Recursive Binding Construct“。

本文从一个简单的版本开始,接着解释了一个更复杂的扩展:

https://www.cs.indiana.edu/~dyb/pubs/fixing-letrec.pdf

票数 5
EN

Stack Overflow用户

发布于 2018-06-02 06:10:06

由于您的示例没有任何过程,也没有实际的表达式,我认为您可以将其实现为:

代码语言:javascript
复制
(let ((x 1) (y 2))
  (+ x y)) 

但是为了支持表单的意图,一个基本的实现可能会这样做:

代码语言:javascript
复制
(let ((x 'undefined) (y 'undefined))
  (let ((tmpx 1) (tmpy 2))
    (set! x tmpx)
    (set! y tmpy))
  (+ x y))

现在。letrec是为了让lambda能够用名字来称呼自己。所以想象一下:

代码语言:javascript
复制
(let ((fib (lambda (n) 
             (if (< n 2) n 
                 (+ (fib (- n 1)) (fib (- n 2)))))))
      (fib 10))

重要的是要理解这是不起作用的以及为什么。将其转换为lambda调用可以很容易地看到:

代码语言:javascript
复制
((lambda (fib)
   (fib 10))
 (lambda (n) 
   (if (< n 2) n 
       (+ (fib (- n 1)) (fib (- n 2))))))

在创建fib之后,您需要以某种方式评估lambda。假设我们这样做:

代码语言:javascript
复制
(let ((fib 'undefined))
  (set! fib (lambda (n) 
              (if (< n 2) n 
                  (+ (fib (- n 1)) (fib (- n 2))))))
  (fib 10))

或者,您也可以使用Z combinator来使其成为纯对象:

代码语言:javascript
复制
(let ((fib (Z (lambda (fib)
                (lambda (n) 
                  (if (< n 2) n 
                      (+ (fib (- n 1)) (fib (- n 2)))))))))  
  (fib 10))

这需要通过实现做更多的工作,但至少你没有改变。要让它与几个相互递归绑定一起工作,可能需要做更多的工作,但我相信这是可行的。

这是正确做到这一点的唯一两种方法。我知道clojure有一个模仿递归的recur,但实际上是一个goto。

对于不从letrec绑定生成闭包的变量,它们的工作方式是let,后来更像是let*,因为Soegaards对修复的回答是向后兼容的,有些人已经对其进行了调整。但是,如果您编写了兼容的代码,就不应该这样认为。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50627845

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档