【问题标题】:Understanding result from Scheme code从 Scheme 代码中理解结果
【发布时间】:2014-07-03 10:05:03
【问题描述】:

我最近一直在玩方案,并提供了以下代码示例。

(define f (lambda (g) (lambda (x) (g (+ (g x) (g x)))))) 
(define e (lambda (x) (* x 3))) 
(define d (f e)) 
(d 4) 

输出是

=> 72

如果有人可以向我提供解释器如何逐步处理此代码并产生结果的概要,这将有助于我理解这种语言。

我的理解非常基础,让我失望的是(d 4),因为我(最初)认为(define d (f e)) 有两个参数。我一直在阅读在线链接中的材料,但似乎找不到我正在寻找的正确解释。

【问题讨论】:

  • (define d (f e)) 定义d 来保存评估(f e) 的结果值,它以e 的值作为参数调用f 引用的函数。

标签: lambda functional-programming scheme closures


【解决方案1】:

为了

(d 4)

要工作,d 必须是一个过程。由于d 是使用

定义的
(define d (f e))

然后

(f e)

必须返回一个过程。 f的方式已经定义好了,它的返回值确实是一个lambda表达式。

返回值

(f e)

(lambda (x) (e (+ (e x) (e x))))

如果你替换 e 代表的东西,你会得到:

(lambda (x) (* (+ (* x 3) (* x 3)) 3))

因此,

(define d (f e))

可以翻译成

(define d (lambda (x) (* (+ (* x 3) (* x 3)) 3)))

现在,

(d 4)

可以翻译成

(* (+ (* 4 3) (* 4 3)) 3)

计算结果为72

【讨论】:

  • (lambda (x) (* (+ (* x 3) (* x 3)) 3))部分,为什么运算符只替换ex 3替换x
  • @Algorithm 由于e 被定义为(lambda (* x 3)),我们可以将(e x) 替换为(* x 3)。希望能回答您的问题。
  • 啊,我想我快到了。我仍在尝试熟悉语法。 (e x) 是对 e 的过程调用,其中参数是 x
【解决方案2】:

我将用substitution model 解释这一点。这个想法是,您可以用它的定义替换一个变量,并用过程主体中的表达式替换一个过程应用程序,并将形式参数扩展到它的 aguments。例如:

(define square (lambda (x) (* x x)))
(square 5)

所以我们从(sqrt 5) 开始,因为它启动进程(不是定义)

(square 5)               ; ==> subst square 
((lambda (x) (* x x)) 5) ; ==> apply x=5
(* 5 5)                  ; ==> 25

现在让我们对您的示例做同样的事情:

(定义 f (lambda (g) (lambda (x) (g (+ (g x) (g x)))))) (定义 e (lambda (x) (* x 3))) (定义 d (fe)) (d 4)

或者我们可以从d 开始,因为它的定义是一个表达式(f e)

(f e) ; subs f ==>
((lambda (g) (lambda (x) (g (+ (g x) (g x))))) e)   ; apply g=e ==>
(lambda (x) (e (+ (e x) (e x))))                    ; subst first e ==>
(lambda (x) ((lambda (x) (* x 3)) (+ (e x) (e x)))) ; apply x=(+ (e x) (e x)) ==>
(lambda (x) (* (+ (e x) (e x)) 3))                  ; subst e+apply x=x ==>
(lambda (x) (* (+ (* x 3) (* x 3)) 3))              ; now this is d

所以实际上fe 现在是无关紧要的,因为根据替换规则你可以改写(define d (lambda (x) (* (+ (* x 3) (* x 3)) 3))。 然后我们使用它的新定义来执行(d 4)

(d 4)                                      ; subst d ==>
((lambda (x) (* (+ (* x 3) (* x 3)) 3)) 4) ; apply x=4 ==>
(* (+ (* 4 3) (* 4 3)) 3)                  ; ==> 72

我已手动完成此操作,但您可以通过在左下方下拉菜单中选择“中级学生”作为语言并按 STEP >| 来自动完成 DrRacket 中的简单方案代码。您的代码有 13 个步骤。但是,手动进行几次以掌握它会有所帮助,并且在观看SICP videoes 后您会更好地理解,如果您完成questions in the book,您会非常好。书籍和视频是免费的,因此您只需花时间付费即可完成计划。

【讨论】:

  • 最好的解释,谢谢!我刚刚阅读了一些关于 lambda 演算的文档,现在这对我来说非常有意义。我开始相信函数式语言的力量。
  • @Sylwester sqr,而不是 sqrt
  • @ChrisJester-Young OMG,你是对的。我想要一个比视频(平方和)更简单的例子,并认为square 很好,并称之为sqrt。更新!谢谢:-)
【解决方案3】:

你的程序相当于

(let ((f (lambda (g) (lambda (x) (g (+ (g x) (g x)))))))
  (let ((e (lambda (x) (* x 3))))
    (let ((d (f e)))
      (d 4))))       

一般来说,应该使用letrec,而不是let,但在这里没有区别。 letrec 允许过程在其主体内引用自己的名称,即递归let 不允许此类引用。例如,定义 f 的 lambda 表达式不包含对 f 的任何引用。

现在,评估继续尝试找出d 的值,将其用作要以4 的值作为参数调用的函数。因此执行应用程序(f e)。一般来说,一个应用程序((lambda (x) ...) v)被简化为(let ((x v)) ...)

(let ((f (lambda (g) (lambda (x) (g (+ (g x) (g x)))))))
  (let ((e (lambda (x) (* x 3))))
    (let ((d (let ((g e))           ; <---
               (lambda (x) (g (+ (g x) (g x)))) )
           ))
      (d 4))))

返回一个闭包:

(let ((f (lambda (g) (lambda (x) (g (+ (g x) (g x)))))))
  (let ((e (lambda (x) (* x 3))))
             (let ((g e))
      (let ((d (lambda (x) (g (+ (g x) (g x))))))
        (d 4)))))       ; <---

现在发现d的值是一个过程,所以执行(d 4)的应用:

(let ((f (lambda (g) (lambda (x) (g (+ (g x) (g x)))))))
  (let ((e (lambda (x) (* x 3))))
    (let ((g e))
      (let ((d (lambda (x) (g (+ (g x) (g x))))))
        (let ((x 4))
          (g (+ (g x) (g x))) )))))    ; <---

(let ((f (lambda (g) (lambda (x) (g (+ (g x) (g x)))))))
  (let ((e (lambda (x) (* x 3))))
    (let ((g e))
      (let ((d (lambda (x) (g (+ (g x) (g x))))))
        (let ((x 4))
          (let ((temp1 (+ (g x) (g x))))    ; <---
            (g temp1) ))))))

这是

......
        (let ((x 4))
          (let ((temp2 (g x))               ; <---
                (temp3 (g x)))               
            (let ((temp1 (+ temp2 temp3)))   
               (g temp1) )))))))           

......
        (let ((x 4))
          (let ((temp2 ( (lambda (x1) (* x1 3)) x ))   ; <---
                (temp3 (g x)))               
            (let ((temp1 (+ temp2 temp3)))   
               (g temp1) )))))))             

......
        (let ((x 4))
          (let ((temp2 (let (x1 x) (* x1 3)))     ; <---
                (temp3 (g x)))               
            (let ((temp1 (+ temp2 temp3)))   
               (g temp1) )))))))             

......
        (let ((x 4))
          (let ((temp2 (let (x1 4) (* x1 3)))     ; <---
                (temp3 (g x)))               
            (let ((temp1 (+ temp2 temp3)))   
               (g temp1) )))))))             

......
        (let ((x 4))
          (let ((temp2             (* 4 3))       ; <---
                (temp3 (g x)))               
            (let ((temp1 (+ temp2 temp3)))   
               (g temp1) )))))))             

等等。这不是 Scheme 实际操作的方式,而是关闭方式。终于到了

......
        (let ((x 4))
          (let ((temp2 12) 
                (temp3 12))               
            (let ((temp1 24))   
               (g temp1) )))))))             ; <---

......
            (let ((temp1 24))   
               ( (lambda (x2) (* x2 3)) temp1) )))))     ; <---

......
               (let (x2 24) (* x2 3)) ))))     ; <---

......
               (* 24 3)  ))))     ; <---

......
               72  ))))           ; []

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-15
    • 2012-01-05
    • 2011-09-10
    • 1970-01-01
    相关资源
    最近更新 更多