[Prev][Next][Index][Thread]
Re: Closures
In article <3B720DA9.2060901@staffware-spokane.com>, Doug Hockin
<dhockin@staffware-spokane.com> wrote:
> I'm new to Dylan and many of the concepts. In the
> Dylan Reference Manual is an example that I can't
> follow. It seems to me that there are errors in
> the text. Am I missing something?
>
> > The following example defines a function that returns score-card
> > methods.
> > The method that is returned is closed over the score parameter. Each
> > time
> > this method is called, it updates the score parameter and returns its
> > new value.
> >
> > define method make-score (points :: <number>)
> > method (increase :: <number>)
> > points := points + increase;
> > end method;
> > end method make-score;
> > define constant score-david = make-score(100)
> > define constant score-diane = make-score(400)
> > score-david(0)
> > fi 100
> > score-david(10)
> > fi 110
> > score-david(10)
> > fi 120
> > score-diane(10)
> > fi 410
> > score-david(0)
> > fi 120
> >
> > Each invocation of make-score creates a new binding for score, so each
> > closure returned by make-score refers to a different binding. In this
> > way,
> > assignments to the variable made by one closure do not affect the value
> > of
> > the variable visible to other closures.
>
> I don't see a "score parameter" anywhere. Does it mean "points"?
Yes, it does.
> Could someone give a blow by blow of how the above works?
What languages have you used previously? You can do exactly the same
thing in many languages, including Lisp, Scheme, Perl, and I think,
recently, Python.
In Perl:
[localhost:~/programs/perl] bruce% cat >score.pl
#!/usr/bin/perl
sub makeScore {
my $points = shift;
sub {
my $increase = shift;
$points += $increase;
}
}
my $david = makeScore(100);
my $diane = makeScore(400);
print &$david(0), "\n";
print &$david(10), "\n";
print &$david(10), "\n";
print &$diane(10), "\n";
print &$david(0), "\n";
[localhost:~/programs/perl] bruce% perl score.pl
100
110
120
410
120
[localhost:~/programs/perl] bruce%
Semantically, the idea is that any function has access to the local
variables and arguments of any functions that it is nested within. This
applies also to such old languages as Pascal and Algol, but not to C
since C doesn't have nested functions (well, gcc supports them, but
standard C doesn't).
The only difference here is that in Pascal such a reference is
considered to be invalid after a function containing such a local
variable returns. So you can, say, pass a comparison function to a sort
procedure, but the comparision function can't be stored into a global
variable or returned from the enclosing function.
i.e. in Pascal you can do this...
procedure foo(var a : array [1..100] of integer)
function less(l : integer, r : integer) : boolean
begin
less := a[l] < a[r]
end
begin
sort(a, less)
end;
...but you can't do return the "less" function from "foo", or store it
into a global variable, and expect it to work afterwards. Of course, in
Pascal, one of the reasons you can't do this is that there's no syntax
that allows it... :-)
if you're more interested in how the nuts and bolts of it work, the
Dylan you showed migth be translated by a suitable compiler into the
following C:
#include <stdio.h>
struct make_score_environment {
int points;
};
struct make_score_closure {
int (*func)(struct make_score_environment *env, int increase);
struct make_score_environment env;
};
int make_score_anon(struct make_score_environment *env, int increase){
return env->points += increase;
}
struct make_score_closure make_score(int points){
struct make_score_closure result;
result.env.points = points;
result.func = make_score_anon;
return result;
}
int main(){
struct make_score_closure david = make_score(100);
struct make_score_closure diane = make_score(400);
printf("%d\n", (*david.func)(&david.env, 0));
printf("%d\n", (*david.func)(&david.env, 10));
printf("%d\n", (*david.func)(&david.env, 10));
printf("%d\n", (*diane.func)(&diane.env, 10));
printf("%d\n", (*david.func)(&david.env, 0));
return 0;
}
Of course if you don't know C either then this isn't going to help much
:-)
-- Bruce
Follow-Ups:
References:
- Closures
- From: Doug Hockin <dhockin@staffware-spokane.com>