临时覆盖 Scheme let 块中的全局定义函数?
temporarily overwrite a globally defined function in Scheme let block?
假设我有以下功能:
(define (g x) (f x))
(define (f x) (+ 1 x))
我想用不同的 f
临时调用g
。例如,像这样:
(let ((f (lambda (x) (+ 2 x))))
(g 5))
我会喜欢上面的代码计算结果为 7,但事实并非如此。相反,它的计算结果为 6,因为 g
在 let
.
的范围外调用 f
有没有办法在不在 let
中重新定义 g
,并且不在 let
中内联 g
定义的整个主体的情况下执行此操作? (实际上,g
可能是一个非常大、复杂的函数)。
我不确定你可以,但我绝不是 Scheme 专家。
我知道你试图在不在 let
中重新定义 g
的情况下实现这一点,但是如何:
(define (h f x) (f x))
(define (g x) (h f x))
(define (f x) (+ 1 x))
(let ((f (lambda (x) (+ 2 x))))
(h f 5))
这样,您可以在当前调用的地方保留 g
的行为。但是如果你想暂时有不同的行为,你可以改为调用 h
。
多一点代码来说明:
(let ((f (lambda (x) (+ 2 x))))
(display (g 5)) ; 6
(newline)
(h f 5)) ; 7
您可以在 g
中使用可选参数来传递 let
表达式中的 f
。
(define (g x . args)
(if (null? args)
(f x)
((car args) x)))
和
(let ((f (lambda (x) (+ 2 x))))
(g 5 f))
您要求的是 'f' 的动态而非词法绑定。 R6RS 和 R7RS 通过参数支持这一点。这会做你想做的事:
(define f (make-parameter (lambda (x) (+ 1 x))))
(define (g x) ((f) x))
(display (g 5))(newline)
(parameterize ((f (lambda (x) (+ 2 x))))
(display (g 5))(newline))
我找到了一种方法来做我想做的事情,虽然我觉得很多人不会考虑这个 kosher:
(define (g x) (f x))
(define (f x) (+ 1 x))
(let ((old-f f))
(set! f (lambda (x) (+ 2 x)))
(let ((ans (g 5)))
(set! f old-f)
ans))
; -> 7
(g 5) ; -> 6
edit 作为对下面评论的回应,我什至不知道 fluid-let
是一回事。它甚至已经在 MIT-Scheme 上运行。这实际上正是我所需要的。如果下面的评论者发布类似这样的答案,它将被接受为答案:
(define (g x) (f x))
(define (f x) (+ 1 x))
(fluid-let ((f (lambda (x) (+ x 2))))
(g 5)) ; -> 7
(g 5) ; -> 6
假设我有以下功能:
(define (g x) (f x))
(define (f x) (+ 1 x))
我想用不同的 f
临时调用g
。例如,像这样:
(let ((f (lambda (x) (+ 2 x))))
(g 5))
我会喜欢上面的代码计算结果为 7,但事实并非如此。相反,它的计算结果为 6,因为 g
在 let
.
f
有没有办法在不在 let
中重新定义 g
,并且不在 let
中内联 g
定义的整个主体的情况下执行此操作? (实际上,g
可能是一个非常大、复杂的函数)。
我不确定你可以,但我绝不是 Scheme 专家。
我知道你试图在不在 let
中重新定义 g
的情况下实现这一点,但是如何:
(define (h f x) (f x))
(define (g x) (h f x))
(define (f x) (+ 1 x))
(let ((f (lambda (x) (+ 2 x))))
(h f 5))
这样,您可以在当前调用的地方保留 g
的行为。但是如果你想暂时有不同的行为,你可以改为调用 h
。
多一点代码来说明:
(let ((f (lambda (x) (+ 2 x))))
(display (g 5)) ; 6
(newline)
(h f 5)) ; 7
您可以在 g
中使用可选参数来传递 let
表达式中的 f
。
(define (g x . args)
(if (null? args)
(f x)
((car args) x)))
和
(let ((f (lambda (x) (+ 2 x))))
(g 5 f))
您要求的是 'f' 的动态而非词法绑定。 R6RS 和 R7RS 通过参数支持这一点。这会做你想做的事:
(define f (make-parameter (lambda (x) (+ 1 x))))
(define (g x) ((f) x))
(display (g 5))(newline)
(parameterize ((f (lambda (x) (+ 2 x))))
(display (g 5))(newline))
我找到了一种方法来做我想做的事情,虽然我觉得很多人不会考虑这个 kosher:
(define (g x) (f x))
(define (f x) (+ 1 x))
(let ((old-f f))
(set! f (lambda (x) (+ 2 x)))
(let ((ans (g 5)))
(set! f old-f)
ans))
; -> 7
(g 5) ; -> 6
edit 作为对下面评论的回应,我什至不知道 fluid-let
是一回事。它甚至已经在 MIT-Scheme 上运行。这实际上正是我所需要的。如果下面的评论者发布类似这样的答案,它将被接受为答案:
(define (g x) (f x))
(define (f x) (+ 1 x))
(fluid-let ((f (lambda (x) (+ x 2))))
(g 5)) ; -> 7
(g 5) ; -> 6