Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否临时覆盖Scheme let block中的全局定义函数?_Scheme_Racket_Lexical Scope_Dynamic Scope_Lexical Closures - Fatal编程技术网

是否临时覆盖Scheme let block中的全局定义函数?

是否临时覆盖Scheme let block中的全局定义函数?,scheme,racket,lexical-scope,dynamic-scope,lexical-closures,Scheme,Racket,Lexical Scope,Dynamic Scope,Lexical Closures,假设我有以下功能: (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可能是一个非常大、复杂的函数)。我不确定您是否可以,但我绝不

假设我有以下功能:

(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
可能是一个非常大、复杂的函数)。

我不确定您是否可以,但我绝不是方案专家

我意识到您试图在不重新定义
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)))


您所要求的是动态绑定,而不是“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))

我找到了一个做我想做的事情的方法,尽管我有很多人不会考虑这个犹太教:< /P>
(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是一件事。它甚至已经在麻省理工学院的计划中发挥了作用。这正是我需要的。如果下面的评论者发布类似于此的答案,则将成为公认的答案:

(define (g x) (f x))

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

(fluid-let ((f (lambda (x) (+ x 2))))
  (g 5)) ; -> 7

(g 5) ; -> 6

这是否仍然需要我将
g
的整个定义粘贴到
let
中?我真正关心的情况是,
g
是一个非常长、复杂的函数,可以多次调用
f
。这个答案能处理那个案子吗?不,我不这么认为。我假设
f
g
是全局定义的?我的建议是创建一个新的过程
h
,并将
g
的主体剪切/粘贴到
h
,其中
h
将过程
f
作为参数。然后,重新定义
g
,以便调用
h
,并传入全局定义的
f
。因此,
g
的行为保持不变,但只要您想用不同的
f
调用
g
,就可以调用
h
并传入不同的
f
。您可以向
g
添加一个参数:
(定义(gfx)(fx))
。然后
(gf5)
将是6或7,这取决于通过的
f
。您要求的是动态范围,这在20世纪60年代被发现不是一个很好的主意。从那以后,词汇范围一直统治着世界。这可以打包成一个宏,我不知道,比如什么。当然,我们需要增加对错误的保护,因此无论发生什么情况,
f
的旧定义都会得到恢复,就像在CL中一样。那么继续/跳远呢?但作为一个简单的用户级实用程序,为什么不呢?
fluid let
正是我想要的;请随意发布一个答案,我会点击acceptor,当然你可以用set来做!和全局变量,但您必须实现代码,以防止异常或调用continuation对象使全局变量处于不一致的状态,这也是线程安全的(另一方面,参数化是常见实现上的线程局部,一些流体实现也是如此)。你们把“球拍”包括在你们的团队中,球拍有参数化,但并没有(我相信)流体出租。更一般地说,parameterize在scheme报告中,fluid let不是。@WillNess是的,你是对的,事实上我一开始确实把Racket作为标签。不知道我为什么这么做,因为我几乎从未使用过它。
(define (g x) (f x))

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

(fluid-let ((f (lambda (x) (+ x 2))))
  (g 5)) ; -> 7

(g 5) ; -> 6