Reputation: 3042
suppose I have the following functions:
(define (g x) (f x))
(define (f x) (+ 1 x))
I would like to temporarily call g
with a different f
. For example, something like this:
(let ((f (lambda (x) (+ 2 x))))
(g 5))
I would like the code above to evaluate to 7, but it doesn't. Instead, it evaluates to 6, since g
calls the f
outside the scope of the let
.
Is there a way to do this without redefining g
inside the let
, and without inlining the entire body of the definition of g
in the let
? (In practice, g
may be a very large, complicated function).
Upvotes: 2
Views: 536
Reputation: 3042
I found a way to do exactly what I wanted, although I have a feeling many people will not consider this 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 In response to the comment below, I wasn't even aware that fluid-let
was a thing. It even already works on MIT-Scheme. That's actually exactly what I needed. If commenter below posts something like this as an answer, it will be made the accepted answer:
(define (g x) (f x))
(define (f x) (+ 1 x))
(fluid-let ((f (lambda (x) (+ x 2))))
(g 5)) ; -> 7
(g 5) ; -> 6
Upvotes: 0
Reputation: 727
What you are asking for is dynamic rather than lexical binding of 'f'. R6RS and R7RS support this with parameters. This will do what you want:
(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))
Upvotes: 2
Reputation: 206607
You could use an optional parameter in g
to pass the f
from the let
expression.
(define (g x . args)
(if (null? args)
(f x)
((car args) x)))
and
(let ((f (lambda (x) (+ 2 x))))
(g 5 f))
Upvotes: 0
Reputation:
I'm not sure that you can, but I'm by no means a Scheme expert.
I realise that you're trying to achieve this without redefining g
inside the let
, but how about:
(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))
That way, you preserve the behaviour of g
where it's currently being called. But where you want to temporarily have a different behaviour, you can call h
instead.
A bit more code for clarification:
(let ((f (lambda (x) (+ 2 x))))
(display (g 5)) ; 6
(newline)
(h f 5)) ; 7
Upvotes: 0