[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Guile Impressions
From: |
Rob Browning |
Subject: |
Re: Guile Impressions |
Date: |
10 May 2001 15:56:35 -0500 |
User-agent: |
Gnus/5.0808 (Gnus v5.8.8) Emacs/20.7 |
John Fitzgerald <address@hidden> writes:
> I am frustrated by the missing documentation, and resorting to code
> reading isn't the best way to answer queries as the answer often
> lies in the dynamic behaviour for which you need to read and
> understand large regions of the program.
And unfortunately, Guile's (use-modules (doc psychic)) is broken ATM.
> Quite possibly. Approaching it from the necessity to grep
> libguile/*.h to find applicable scm_ and SCM_ items then trying to
> decipher the differences between some of them probably isn't the
> best, but from that viewpoint it does appear to have grown
> haphazardly rather than have been planned.
Right. There definitely seem to me to be bits of the scm_ interface
that are probably too interpreter specific to be often useful as a
general interface, especially one we want to maintain compatibility
with in the long run, so I think we probably need to make it clear
which functions are considered officially part of the public
interface. There's been some discussion about that on guile-devel
lately, in fact.
> Perhaps what is needed is a glossary of terms like 'closure',
> 'fluid' and 'continuation' (to name some Scheme language ones) which
> we newbies can refer to to get an plain English description.
OK. I'm just writing this off the top of my head, but I figured it
might be useful. Here are some not-so-polished attempts to describe
closures and continuations practically to a C-esque audience.
Closure for C programmers:
(This isn't a complete description, but should get people on the
right track...)
Imagine being able to define some local variables inside a function
foo and then, right there in the code for foo, create a *new*
function bar that had access to all those local variables. Imagine
further that you could then return the pointer to your new function,
and when other people called it, it would still be able to access
the local variables available when it was created. Imagine still
further that every time you called foo in order to create a copy of
bar, each copy had it's own private set of those variables. The
code might look something like this (though it's obviously not legal
C code):
int (*counter)()
foo()
{
int local_counter = 0;
int bar()
{
return local_counter++;
}
return bar;
}
Given that definition, you would be then able to say:
int (*counter)() counter_a = foo();
int (*counter)() counter_b = foo();
printf("a %d\n", counter_a());
printf("a %d\n", counter_a());
printf("b %d\n", counter_b());
printf("b %d\n", counter_b());
printf("b %d\n", counter_b());
printf("b %d\n", counter_b());
printf("a %d\n", counter_a());
printf("a %d\n", counter_a());
and the output would be
0
1
0
1
2
3
2
3
Note that I'm not declaring local_counter as a static because, even
though this is not legal code anyway, I figured it would imply to C
programmers that there was only one copy of local_counter in the
entire program, which is not true. Each instance of bar will have
it's own private copy of local_counter.
Note too that if you created several functions inside foo at the
same time and returned them all, they would all share the same copy
of local_counter, and could communicate through it among themselves
:>
If C had closures, you would often not really need to add "void
*user_data" pointers as arguments to your callback routines. You
could just build the function you need, that has access to the data it
needs when you like. This, of course, is much more powerful when
coupled with a garbage collected language
For example. Imagine you had were using a GUI button press callback
that didn't support *any* arguments, but you wanted to be able write
*one* button_press callback that you could use for several buttons
and each should print a different message. You could do that with
closures like this:
/* callback prototype -- GUI designer was stingy with args ... */
void (*button_press)();
/* we work around that by creating a callback creator function */
void (*press_func)
make_button_press_func(const char *message)
{
void what_to_do_when_pressed()
{
printf("%s", message);
}
return what_to_to_when_pressed;
}
/* and then we can use it like this */
gui_button button_a = gui_make_button();
gui_button button_b = gui_make_button();
gui_button button_c = gui_make_button();
gui_button_set_push_callback(button_a,
make_button_press_func("You pushed A/\n"));
gui_button_set_push_callback(button_b,
make_button_press_func("You pushed B/\n"));
gui_button_set_push_callback(button_c,
make_button_press_func("You pushed C/\n"));
etc. Nifty, huh? We just don't need for the callback to have any
user_data style arguments, and when the language is garbage
collected, you don't have to worry about the allocation/deallocation
of the strings involved.
Continuations (continued from above example):
Imagine that at any point in your C program, you could call a
function that would return to you a newly constructed function that
if ever called, would jump you right back to the current place in
the program, including preserving the stack and all of the visible
variable bindings. It's like a time-warp function, with the main
exception that any global variables that have been modified won't be
reset to the values they had when the time-warp function was
created. That time-warp function pointer is a continuation. It's
kind of like a longjmp on steroids.
(This is actually a definition most appropriate to the
call-with-current-continuation function, but it hopefully gets at
least the "flavor" of a continuation across.)
--
Rob Browning <address@hidden> PGP=E80E0D04F521A094 532B97F5D64E3930
RE: Guile Impressions, John Fitzgerald, 2001/05/10
RE: Guile Impressions, John Fitzgerald, 2001/05/11