临时覆盖 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,因为 glet.

的范围外调用 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