从 sicp 宏中的周围抽象中捕获变量
Capturing variables from surrounding abstractions in sicp macros
我正在尝试在 sicp 中编写一个更高级别的函数,它采用可变数量的 单参数函数 和 returns 另一个函数,它是所有传递的组合功能。假设更高级别的函数被命名为 compose
然后做 (compose f g)
应该 return 函数 fog
或 f(g(x))
其中 f 和 g 是一些 单参数函数。
我正在使用 sicp 的 define-syntax 构造来实现这一点,到目前为止我有以下代码:
(define-syntax apply-to-all-functions
(syntax-rules ()
((apply-to-all-functions f) (f x))
((apply-to-all-functions f g) (f (apply-to-all-functions g)))
((apply-to-all-functions f . g) (f (apply-to-all-functions . g)))
))
(define-syntax compose
(syntax-rules (x)
((compose) (lambda (x) x))
((compose g) (lambda (x) (apply-to-all-functions g)))
((compose . g) (lambda (x) (apply-to-all-functions . g)))
))
在此代码中,我试图捕获绑定在 function/macro compose
中的 lambda
中的 x
,但是当我创建复合函数并调用它在某个值上,我得到标识符 x
未绑定的错误。
有人可以解释一下如何在上述设置中捕获变量或以其他方式解决此问题。
谢谢!:)
... or some other way to solve this problem.
我不明白为什么 OP 代码试图在这里使用宏来创建高阶过程。 compose
使用一个或多个过程参数的过程可以使用过程定义的点语法轻松编写。
(define (compose f . fs)
(if (null? fs)
(lambda (x) (f x))
(let ((g (apply compose fs)))
(lambda (x) (f (g x))))))
此处,当仅提供一个参数时,将 f
应用于单个参数 x
的过程是 returned。否则,将 f
应用于剩余过程参数的组合,并将最终过程参数应用于单个参数 x
的过程是 returned.
这里有一个REPL演示:
> (define (double x) (* 2 x))
> (define (reciprocal x) (/ 1 x))
> (define (square x) (* x x))
> (define (add1 x) (+ x 1))
> (define doros (compose double reciprocal square))
> (define rodos (compose reciprocal double square))
> (doros 4)
1/8
> (rodos 4)
1/32
> (define dosoaor (compose double square add1 reciprocal))
> (define soroaod (compose square reciprocal add1 double))
> (= (dosoaor 4)
(double (square (add1 (reciprocal 4)))))
#t
> (dosoaor 4)
25/8
> (= (soroaod 4)
(square (reciprocal (add1 (double 4)))))
#t
> (soroaod 4)
1/81
组合过程 doros
应首先对其参数求平方,然后取结果的倒数,最后 return 两倍结果。因此,(doros 4)
应该评估为 (* 2 (/ 1 (* 4 4)))
==> 1/8
,如上面的 REPL 演示所示。
同样,rodos
应该先对它的参数求平方,然后将结果加倍,最后取该结果的倒数。因此 (rodos 4)
应该评估为 (/ 1 (* 2 (* 4 4)))
==> 1/32
,匹配 REPL 结果。
四个程序组成的测试也成功了。
我正在尝试在 sicp 中编写一个更高级别的函数,它采用可变数量的 单参数函数 和 returns 另一个函数,它是所有传递的组合功能。假设更高级别的函数被命名为 compose
然后做 (compose f g)
应该 return 函数 fog
或 f(g(x))
其中 f 和 g 是一些 单参数函数。
我正在使用 sicp 的 define-syntax 构造来实现这一点,到目前为止我有以下代码:
(define-syntax apply-to-all-functions
(syntax-rules ()
((apply-to-all-functions f) (f x))
((apply-to-all-functions f g) (f (apply-to-all-functions g)))
((apply-to-all-functions f . g) (f (apply-to-all-functions . g)))
))
(define-syntax compose
(syntax-rules (x)
((compose) (lambda (x) x))
((compose g) (lambda (x) (apply-to-all-functions g)))
((compose . g) (lambda (x) (apply-to-all-functions . g)))
))
在此代码中,我试图捕获绑定在 function/macro compose
中的 lambda
中的 x
,但是当我创建复合函数并调用它在某个值上,我得到标识符 x
未绑定的错误。
有人可以解释一下如何在上述设置中捕获变量或以其他方式解决此问题。
谢谢!:)
... or some other way to solve this problem.
我不明白为什么 OP 代码试图在这里使用宏来创建高阶过程。 compose
使用一个或多个过程参数的过程可以使用过程定义的点语法轻松编写。
(define (compose f . fs)
(if (null? fs)
(lambda (x) (f x))
(let ((g (apply compose fs)))
(lambda (x) (f (g x))))))
此处,当仅提供一个参数时,将 f
应用于单个参数 x
的过程是 returned。否则,将 f
应用于剩余过程参数的组合,并将最终过程参数应用于单个参数 x
的过程是 returned.
这里有一个REPL演示:
> (define (double x) (* 2 x))
> (define (reciprocal x) (/ 1 x))
> (define (square x) (* x x))
> (define (add1 x) (+ x 1))
> (define doros (compose double reciprocal square))
> (define rodos (compose reciprocal double square))
> (doros 4)
1/8
> (rodos 4)
1/32
> (define dosoaor (compose double square add1 reciprocal))
> (define soroaod (compose square reciprocal add1 double))
> (= (dosoaor 4)
(double (square (add1 (reciprocal 4)))))
#t
> (dosoaor 4)
25/8
> (= (soroaod 4)
(square (reciprocal (add1 (double 4)))))
#t
> (soroaod 4)
1/81
组合过程 doros
应首先对其参数求平方,然后取结果的倒数,最后 return 两倍结果。因此,(doros 4)
应该评估为 (* 2 (/ 1 (* 4 4)))
==> 1/8
,如上面的 REPL 演示所示。
同样,rodos
应该先对它的参数求平方,然后将结果加倍,最后取该结果的倒数。因此 (rodos 4)
应该评估为 (/ 1 (* 2 (* 4 4)))
==> 1/32
,匹配 REPL 结果。
四个程序组成的测试也成功了。