Временно перезаписать глобально определенную функцию в блоке let block?
Предположим, у меня есть следующие функции:
(define (g x) (f x))
(define (f x) (+ 1 x))
Я хотел бы временно позвонить g
с другим f
, Например, что-то вроде этого:
(let ((f (lambda (x) (+ 2 x))))
(g 5))
Я хотел бы, чтобы код выше оценивать до 7, но это не так. Вместо этого он оценивается в 6, так как g
вызывает f
выходит за рамки let
,
Есть ли способ сделать это без переопределения g
внутри let
и без включения всего тела определения g
в let
? (На практике, g
может быть очень большой, сложной функцией).
4 ответа
Я нашел способ сделать именно то, что я хотел, хотя у меня есть чувство, что многие люди не сочтут это кошерным:
(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
То, что вы просите, - это динамическое, а не лексическое связывание '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))
Вы можете использовать необязательный параметр в g
пройти f
от let
выражение.
(define (g x . args)
(if (null? args)
(f x)
((car args) x)))
а также
(let ((f (lambda (x) (+ 2 x))))
(g 5 f))
Я не уверен, что вы можете, но я ни в коем случае не эксперт Схемы.
Я понимаю, что вы пытаетесь достичь этого без переопределения 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