(define (g f n)
(let loop ((i 0) (s 0))
(if (< i n)
(loop (+ i 1) (+ (f) s))
s)))
Function g makes n calls to f, cumulating its returned values.
Function g is called several times, let say in some other loop.
(let loop2 ((j 0))
...
... (g f j) ...
(loop2 (+ j 1))
... )
We want to change f such that on its first call by g, f does some
initialization. Only on the first call by g should an initialization
be done by f. For example, f opens a temporary file, setup a random
number generator, etc. Note that on a second call to g, another
initialization should be done by f.
We do not want to change g, or the code calling it, like the term
(g f j) above.
In essence, we only want to modify f to do its initialization without
modifying the code that calls f.
The puzzle is: Is there a way to do that in Scheme?
Note: the following code does not work since when f is called a second time
by g, no new initialization will be done.
;; The old definition of f.
(define fprime
(lambda ()
... ))
;; The new f
(define f
(let ((initialized? #f))
(lambda ()
(if initialized?
(fprime)
(begin ;; initialization block
...
(set! initialized? #t)
(fprime)
)))))
There is no way to do it in any language without modifying
G in *some* way. There is no way for F to know if G has
returned a value, so it cannot know if the current call is
a `new' one.
That is a logical impossibility. You must change g. In fact you don't have
to change f at all. The exception to this would be to assume some runtime
specific code which examines the call stack so that f can hook g's
invocation frame.
jim
> We do not want to change g, or the code calling it, like the term
> (g f j) above.
Others already said that this is impossible, but you can cheat your
way through by modifying g after it is defined:
(set! g
(let ((orig-g g))
(lambda args
(initializa-f)
(apply orig-g args))))
It does change `g', but not its original definition.
--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://www.barzilay.org/ Maze is Life!
Yet I find this example instructive. In practice this situation arises
often. A (pure) function is modified to maintain a state. In that case
it becomes necessary to analyze all components that use that function
and modify the code accordingly.
For the example, the function f should do its initialization at the
point where g is called or right before several iterations is done
using f by g. This is the concept of closure creation, or creation of
an object.
The promotion of a function to an object (closure) can no longer be
done without revising the code.
It is true that the concept of closure embodies the concept of object.
Yet in a object oriented language, the programmer is made concious of
the need of a ``new object'' and write the code accordingly: In our
case, the programmer would have requested a new f, in g, before doing
all iterations. A Scheme programmer does not think that way (and often
refuses to think that way) and does not program as precisely.
-- Mario
> It is true that the concept of closure embodies the concept of
> object. Yet in a object oriented language, the programmer is made
> concious of the need of a ``new object'' and write the code
> accordingly: In our case, the programmer would have requested a new
> f, in g, before doing all iterations. A Scheme programmer does not
> think that way (and often refuses to think that way) and does not
> program as precisely.
But if you put it this way, then you're not really taling about
changing
(define (g ...)
(... (f ...) ...))
so it will initialize f -- you talk about creating a closure as an
object which is something every Scheme programmer knows how to do. It
will look like this:
(define (g ...)
(let ((my-f (f ...init-values...)))
(... (my-f ...) ...)))
so f is a function that will create the closure which will be used:
(define (f ...init-args...)
(let ((blah ...) ...)
(lambda (f's-args) ...)))