I have defined a function called fold-files-proc, which is called by
the standard Scheme fold-files function. I want to be able to write
something like:
(define (fold-files-proc start-pathname symbol accum)
(if (empty? accum)
(set root accum) ; <=== this isn't quite right
(cons (create-node root start-pathname symbol) accum)))
except that Scheme doesn't like the line
(set root accum)
The variable root is local to the function.
What should I be doing?
Here is an example, where the variable
counter is made "persistent" for the
function counting-display.
(define counting-display 'uninitialized)
(let ([counter 0])
(set! counting-display
(lambda (x . more)
(if (null? more)
(begin
(set! counter (+ counter 1))
(display x))
(display counter))
(newline))))
>(counting-display 'a)
a
> (counting-display 'b)
b
> (counting-display 'show 'me)
2
--
Jens Axel Søgaard
Using lexical scope.
The usual method for creating functions with persistent local
variables is to define a higher-order function that builds them
for you (because you'll probably want more than one). Such
expressions use a lambda (typically syntactic-sugared as let)
to create a lexical region of code within which the arguments of
the lambda are visible. The function that uses those arguments as
persistent variables is then defined inside that lexical region
and has access to those variables.
Here is such a function in its 'canonical' form, which creates a
numeric accumulator.
(define make-accumulator
(lambda () ; this lambda defines the routine being bound to make-accumulator
(lambda (totl) ; this lambda is an 'anonymous' function called with arg of 0
(lambda (a) ; this lambda defines the routine being returned from make-accumulator.
(begin
(set! totl (+ totl a))
totl)))
0)) ; the zero here is the argument to the anonymous function.
=> make-accumulator
Here is the usual sugared syntax for it, rearranging the second
lambda into a let form and folding the first into an alternate
syntax of define.
(define (make-accumulator) ; <= first lambda sugared into this define.
(let ((totl 0)) ; <= second lambda sugared, becomes a let form.
(lambda (a) ; <= third lambda, the routine to be returned.
(begin
(set! totl (+ totl a))
totl)))) ; <= arg to second lambda has moved up into the let form.
either way, this creates a function which returns functions. And the
functions it returns each have access to their own little "static local
variable" named totl, and can set! it.
(define accum (make-accumulator)) =>accum
(define accum2 (make-accumulator)) =>accum2
(accum 2) => 2
(accum2 3) => 3
(accum 5) => 7
(accum2 -4) => -1
(accum 3) => 10
(accum2 5) => 4
(accum 0) => 10
In this example, I created two accumulators, accum and accum2. As
you can see, each has its own totl.
I hope you find this answer helpful. It's not directly addressing
the particular appliction you asked about, but understanding it
should give you the means to solve your problem.
Bear
For the inexperienced, it is worth pointing out that the above code
could be simplified to the version shown below. The version shown
above, with an initial definition as uninitialized and then a set! to
the real procedure, is only useful in that it illustrates a general
pattern that can be applied when several procedures need to share the
same state variables -- a situation that doesn't arise here.
(define counting-display
(let ((counter 0))
(lambda (x . more)
(if (null? more)
(begin
(set! counter (+ counter 1))
(display x))
(display counter))
(newline))))
-Max Hailperin
Associate Professor of Computer Science
Gustavus Adolphus College
800 W. College Ave.
St. Peter, MN 56082
USA
http://www.gustavus.edu/~max/
> > What should I be doing?
>
> Using lexical scope.
> I hope you find this answer helpful. It's not directly addressing
> the particular appliction you asked about, but understanding it
> should give you the means to solve your problem.
That's great, thanks. I had in mind a general "how do you do it"
question regarding persistence, rather than just the specific issue
that I was tackling, anyway.
And thanks to the other respondants, too.
> That's great, thanks. I had in mind a general "how do you do it"
> question regarding persistence, rather than just the specific issue
> that I was tackling, anyway.
I'll recommend reading this section of SICP.
<http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#%_sec_3.1>
By the way, isn't the word "persistence" used to indicate that values
are kept from one program invocation to another (i.e. saved on disk or database) ?
A variable that keeps it's value from one function invocation to another is
in the C programming language called a static variable. Whether this coincides
with the terms normally used in semantics, I'm not quite sure.
--
Jens Axel Søgaard
> <http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#%_sec_3.1>
Thanks, I'll look into it. SICP is a book that I'd like to read, but
it's usually awkward for me to view it online. I can't seem to find a
download file for it in order to read it offline.
> By the way, isn't the word "persistence" used to indicate that values
> are kept from one program invocation to another (i.e. saved on disk or
> database) ?
>
> A variable that keeps it's value from one function invocation to another is
> in the C programming language called a static variable. Whether this
> coincides
> with the terms normally used in semantics, I'm not quite sure.
Apologies for the confusion - I meant static.
Thanks for code snippet, by the way. It will be a while before I
convince myself exactly how it works. Very mysterious - a local value
that still exists even though the function has returned.
(define counting-display
(let ([counter 0])
(lambda (x . more)
(if (null? more)
(begin
(set! counter (+ counter 1))
(display x))
(display counter))
(newline))))
>> <http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#%_sec_3.1>
> Thanks for code snippet, by the way. It will be a while before I
> convince myself exactly how it works. Very mysterious - a local value
> that still exists even though the function has returned.
Note the variable COUNTER is bound *outside* the function.
The scope of the variable is body of the let-expression.
Seen from inside the lambda body there is no difference
between counter and a global variable. In fact, the
following version also works:
(define counter 0)
(define counting-display
(lambda (x . more)
(if (null? more)
(begin
(set! counter (+ counter 1))
(display x))
(display counter))
(newline)))
The only difference is that the scope of counter now is the entire top-level.
What you should focus on, is the scope of the variable (i.e. how the variable
is bound) and not on how it is used.
I hope, it's a little less mysterious now. Again, the explanation in SICP
is very good.
--
Jens Axel Søgaard
> By the way, isn't the word "persistence" used to indicate that
> values are kept from one program invocation to another (i.e. saved
> on disk or database) ?
Depends which language camp you're in. C calls these things "static",
which of course they aren't. "persistent across calls" is more
precise, but it's also too verbose, so sometimes it gets shortened to
"persistent" despite the possible confusion with "persistent across
processes", "persistent across reboots", and so on. The concept goes
by other names as well.
--
$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}}
split//,"ten.thgirb\@badanoj$/ --";$\=$ ;-> ();print$/
> Jens Axel Søgaard <use...@jasoegaard.dk> writes:
>
>
>>By the way, isn't the word "persistence" used to indicate that
>>values are kept from one program invocation to another (i.e. saved
>>on disk or database) ?
>
>
> Depends which language camp you're in. C calls these things "static",
> which of course they aren't. "persistent across calls" is more
> precise, but it's also too verbose, so sometimes it gets shortened to
> "persistent" despite the possible confusion with "persistent across
> processes", "persistent across reboots", and so on. The concept goes
> by other names as well.
The keyword "static" in C is intended to refer to how the memory for the
variable is allocated. Compare "auto" and "extern".
I've only heard the term "persistence" used in the sense Jens Axel
Søgaard mentions.
-thant
they have static addresses - unlike automatic variables (which gives you
the least used C variable qualifiers) that automaticly get a unused
address assigned to themselves.
> precise, but it's also too verbose, so sometimes it gets shortened to
> "persistent" despite the possible confusion with "persistent across
> processes", "persistent across reboots", and so on. The concept goes
> by other names as well.
most literature appears to use 'persistent' for things that do in
fact persist over all of these by being stored in a database.
>
--
Sander
+++ Out of cheese error +++
Try: wget -r http://mitpress.mit.edu/sicp/full-text/book/book.html
--
Geoffrey S. Knauth | http://knauth.org/gsk
> Try: wget -r http://mitpress.mit.edu/sicp/full-text/book/book.html
Thanks.
Although I actually used WinHTTrack Website Copier.