暂时覆盖Scheme let块中的全局定义函数?

时间:2018-02-22 03:47:17

标签: scheme racket lexical-scope dynamic-scope lexical-closures

假设我有以下功能:

(define (g x) (f x))
(define (f x) (+ 1 x))

我想暂时使用不同的 g来呼叫f。例如,像这样:

(let ((f (lambda (x) (+ 2 x))))
  (g 5))

我会喜欢上面的代码来评估为7,但事实并非如此。相反,它评估为6,因为gf 调用{/ 1}}的范围

如果没有在let内重新定义g,并且没有在let中内联g的全部内容,是否有办法做到这一点? (实际上,let可能是一个非常庞大,复杂的功能。)

4 个答案:

答案 0 :(得分:1)

你要求的是动态而不是词汇绑定' 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))

答案 1 :(得分:0)

我不确定你能不能,但我绝不是计划专家。

我意识到您正在努力实现这一目标,而无需在g内重新定义let,但如何:

(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

答案 2 :(得分:0)

您可以使用g中的可选参数从f表达式传递let

(define (g x . args)
  (if (null? args)
    (f x)
    ((car args) x)))

(let ((f (lambda (x) (+ 2 x))))
  (g 5 f))

答案 3 :(得分:0)

我找到了一种完全符合我想要的方法,尽管我觉得很多人都不会考虑这个犹太人:

(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

编辑为了回应下面的评论,我甚至都不知道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