[英]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
中包含printf
的make-add-suffix
版本
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.