简体   繁体   English

Racket 中 lambda 函数的求值顺序

[英]Evaluation order of lambda functions in Racket

Currently working through the Racket Guide at https://docs.racket-lang.org and reading up on lambda functions.目前正在https://docs.racket-lang.org阅读球拍指南并阅读 lambda 函数。 The explanation of their usefulness is lucid, but I am not sure I quite grasp the order in which such functions are evaluated.对它们的用处的解释很清楚,但我不确定我是否完全掌握了评估这些函数的顺序。 Consider the following example from the Guide:考虑指南中的以下示例:

(define (twice f v)
  (f (f v)))

(define (make-add-suffix s2)
  (lambda (s) (string-append s s2)))

(twice (make-add-suffix "!") "hello")

The function call to twice here is said to evaluate to "hello!!"此处对twice的函数调用的结果是"hello!!" . . Here is my guess at what the evaluation process looks like:以下是我对评估过程的猜测:

(twice (make-add-suffix "!") "hello")

((make-add-suffix "!") ((make-add-suffix "!") "hello")

((make-add-suffix "!") (string-append "hello" "!"))

(string-append (string-append "hello" "!") "!")

(string-append "hello!" "!")

"hello!!"

Is this an accurate assessment, or have I missed something?这是一个准确的评估,还是我错过了什么?

Slogan : The outermost and left-most nested expression should be evaluated first.口号:最外面和最左边的嵌套表达式应该首先被评估。

(twice (make-add-suffix "!") "hello")

; (define (f x) ...) is short for (define f (lambda (x) ...)) so,
; = { substitute twice with  (lambda (f v) (f (f v)))}

((lambda (f v) (f (f v))) (make-add-suffix "!") "hello")

; = { substition of make-add-suffix with (lambda (s2) (lambda (s) (string-append s s2)))}

((lambda (f v) (f (f v)))
 ((lambda (s2) (lambda (s) (string-append s s2))) "!")
 "hello")

Terminology before we move on:在我们继续之前的术语:

  • Beta Reduction: ((lambda (x-1 ... xn) f-body) v-1 ... vn) == f-body with all occurrences of x-1 ... xn replaced with v-1 ... vn , respectively. Beta 缩减: ((lambda (x-1 ... xn) f-body) v-1 ... vn) == f-body将所有出现的x-1 ... xn替换为v-1 ... vn ,分别。

  • Call by Value: The arguments of a function call are evaluated before beta reduction.按值调用:函数调用的参数在减少 beta 之前进行评估。

; = { beta-reduction of ((lambda (s2) (lambda (s) (string-append s s2))) "!") }

((lambda (f v) (f (f v))) (lambda (s) (string-append s "!")) "hello")

; = { beta-reduction of the whole expression }

((lambda (s) (string-append s "!"))
 ((lambda (s) (string-append s "!")) "hello"))

; = { beta-reduction of the expression in the argument position first }

((lambda (s) (string-append s "!")) (string-append "hello" "!"))

; ... and the rest is easy:
((lambda (s) (string-append s "!")) "hello!")
(string-append "hello!" "!")
"hello!!"

A different way of getting to the same answer: DrRacket includes a "Stepper" tool for exactly this purpose.获得相同答案的不同方式:DrRacket 包含一个“步进器”工具,正是为了这个目的。 If you set the language level to "Intermediate Student with Lambda" and click on the "Step" button, you should be able to see the evaluation of your program as a sequence of steps, as thrvshl describes.如果您将语言级别设置为“使用 Lambda 的中级学生”并单击“步骤”按钮,您应该能够将程序的评估视为一系列步骤,如 thrvshl 所述。

EDIT: the evaluation strategy you describe, where the first argument to twice is substituted for each of the instances of x in the definition of twice , is called "call-by-name" evaluation, and associated with laziness a la Haskell.编辑:你描述的评估策略,其中的第一个参数twice被替换为每个实例的x中的定义twice ,被称为“呼叫按姓名”的评价,并与懒惰一拉哈斯克尔有关。 To see the difference, consider a version of make-add-suffix that includes a printf in the inner lambda要查看差异,请考虑在内部lambda中包含printfmake-add-suffix版本

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM