使用方案中的参数调用不带参数的函数

时间:2019-02-24 21:27:50

标签: scheme

此代码如何工作?这些函数似乎都没有参数,但是您仍然可以使用参数来调用它

(define (make-add-one)
  (define (inc x) (+ 1 x))
  inc)

(define myfn (make-add-one))

(myfn 2)

这将运行并返回3。

2 个答案:

答案 0 :(得分:0)

让我们使用替换规则。 make-add-one可以这样重写:

(define make-add-one (lambda () 
  (define inc (lambda (x) (+ 1 x))
  inc))

由于inc刚刚返回,因此我们可以进一步简化它:

(define make-add-one (lambda () 
  (lambda (x) (+ 1 x)))

现在myfn可以用lambda包含在其中的代码替换对make-add-one的调用:

(define myfn (make-add-one)) ; ==
(define myfn (lambda (x) (+ 1 x)))

最后,我们可以在上次通话中使用替换规则:

(myfn 2)                 ; ==
((lambda (x) (+ 1 x)) 2) ; ==
(+ 1 2)                  ; ==
3

现在make-add-one所产生的新功能与其所产生的所有其他功能相同。它实际上并没有添加任何东西。此示例在其中有用的一个很好的示例:

(define (make-add by-what)
  (lambda (value) (+ value by-what)))

(define inc (make-add 1))
(define add5 (make-add 5))

(map add5 '(1 2 3)) ; ==> (6 7 8)
(map inc '(1 2 3))  ; ==> (2 3 4)

只是看看是一样的:

(add5 2)                         ; ==
((make-add 5) 2)                 ; ==
((lambda (value) (+ value 5)) 2) ; ==
(+ 2 5)                          ; ==
; ==> 7

这是如何工作的。在词法作用域语言中,所有lambda形式都从创建它的作用域中捕获未绑定在其自己的参数列表中的变量。这称为闭包。一个简单的例子在这里:

(define x 10)
(define test 
  (let ((x 20)
    (lambda (y) (+ x y))))
(test 2) ; ==> 22

因此,在方案test中使用x中的let,即使该范围已退出,因为lambda是在该范围中创建的。在动态范围的语言中,(test 2)将返回12,并且前面的两个示例还将产生其他结果和错误。

词法作用域首先出现在Algol,它是所有C语言家族语言(如C,java,perl)的前身。 Scheme大概是第一个被轻描淡写的语言,它是语言本身的基本设计。如果不关闭,Scheme的第一个版本与其宿主语言MacLisp相同。

答案 1 :(得分:0)

inc中移除make-add-one的定义:

(define (inc x) (+ 1 x))

(define (make-add-one)
  inc)

现在,表达式(make-add-one)inc相同,而inc显然是带有一个参数的过程。
换句话说,不带参数调用make-add-one会产生一个带有一个参数的过程。

您可以使用替代方法进行评估:

    (myfn 2)
==> ((make-add-one) 2)
==> (inc 2)
==> (+ 1 2)
==> 3