Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Nice historical explanation of when and why term "closure" came into use

15 views
Skip to first unread message

HL

unread,
Sep 17, 2006, 8:05:17 PM9/17/06
to
Hi --

I've just stumbled upon this explanation by Max Hailperin on the
historical context when the term "closure" came into use.
This is from the PLT mailing list and can found at:
http://www.cs.utah.edu/plt/mailarch/plt-scheme-2001/msg00226.html

=========================================================================

From: Brent Fulgham
Date: Tue, 6 Feb 2001 09:19:14 -0800

I think one final problem is that SICP makes the point that there
are conflicting definitions of "closure". Some of the books missing
the term "closure" from the index might have used a different term
so as not to confuse it with the "mathematical" definition, ...

That is a pretty good reason to leave "closure" out, but in the case
of at least one textbook -- the one I co-authored -- it isn't the
actual reason that motivated us. I explained that in a privately
emailed reply a moment ago to "bogo." Since this off-topic thread
seems to be be continuing with or without my provocation, I herewith
include it for the rest of you:

Date: Tue, 6 Feb 2001 09:55:39 -0600
From: Michael Bogomolny
...
From a teaching perspective, Concrete Abstractions (Hailperin, Kaiser,
Knight; Brooks/Cole Publishing Company) and Simply Scheme (Harvey and
Wright; MIT Press) are both good books. However, they both fail the
"closure test". ...

Thanks for the endorsement. I probably shouldn't take our failure on
the "closure test" as something to feel defensive about (after all, we
are in good company), but I thought I'd offer some perspective on
*why* we didn't include this vocabulary term. Instead, we simply use
"procedure".

The reason is that "closure" only makes sense in a particular
historical context, where procedures had previously been left "open",
that is with free variables not associated with any particular
binding. This was the case in various pre-Scheme Lisps, and lead to
what was known as the "funarg problem," short for "functional
argument", though it also was manifested when procedures were used in
other first-class ways than as arguments, for example, as return
values, where it was confusingly called the "upward funarg problem"
(by contrast to the "downward funarg problem," where the arg was
genuinely an arg). The "funarg problem" is what logicians had been
calling "capture of free variables," which occurs in the lambda
calculus if you do plain substitution, without renaming, in place of
proper beta-reduction.

So anyhow, an evolutionary milestone in the development of the Lisp
family of languages was the realizations that procedures should be
"closed", that is, converted into a form where all the variables are
bound rather than free. (The way this is normally done, as others
have written in this thread, is by associating the procedure text,
which still has free variables, with a binding environment that
provides the bindings.)

Because this was such a big deal in terms of the languages' evolution,
Lisp hackers took to using the word "closure" rather than just
"procedure" to emphasize that they were talking about this great new
lexically scoped kind of procedure.

As with so many words, it stuck, and people continued using it long
after the distinction it was making ceased to be relevant. (When was
the last time you saw a procedure that hadn't been closed?)

I find this kind of anachronism endearing, just like I grinned a bit
when I recently caught myself calling my compilers textbook the "red
dragon book" -- a name that distinguishes it from the "green dragon
book," which has been extinct for a decade and a half. But I would
never consciously teach a new student to say "red dragon book" rather
than just "dragon book." And I would never consciously teach a new
student to say "closure" rather than just "procedure."

So that's the reason we left it out of our book -- it is a name that
makes a distinction no longer relevant, and which would require
historical context to explain that would distract from the main issues
at hand. (Of course, the distinction may be relevant in other
contexts, like a programming languages course where you are learning
about how languages work, and how else they could work. So in EOPL it
may make perfect sense.) -max

=========================================================================

Paul Rubin

unread,
Sep 17, 2006, 8:06:39 PM9/17/06
to
HL <n...@nowhere.com> writes:
> I've just stumbled upon this explanation by Max Hailperin on the
> historical context when the term "closure" came into use.

Kind of interesting, but it's become the normal word for such things
and trying to escape from it may have done readers a disservice. The
terms "car" and "cdr" have their origins in Jurassic-era IBM mainframe
computers, but Lispers still use them and everyone knows what they
mean.

Barry Margolin

unread,
Sep 17, 2006, 9:06:17 PM9/17/06
to
In article <86y7sik...@agora.my.domain>, HL <n...@nowhere.com> wrote:

> I've just stumbled upon this explanation by Max Hailperin on the
> historical context when the term "closure" came into use.
> This is from the PLT mailing list and can found at:
> http://www.cs.utah.edu/plt/mailarch/plt-scheme-2001/msg00226.html

...


> Because this was such a big deal in terms of the languages' evolution,
> Lisp hackers took to using the word "closure" rather than just
> "procedure" to emphasize that they were talking about this great new
> lexically scoped kind of procedure.
>
> As with so many words, it stuck, and people continued using it long
> after the distinction it was making ceased to be relevant. (When was
> the last time you saw a procedure that hadn't been closed?)

How about almost all conventional programming languages, as well as some
still-popular Lisp dialects such as Emacs Lisp? So unless you assume
the readers have no other programming experience, it seems to me that
it's important to remember this significant difference between
procedures in Scheme/CL and most other languages.

Furthermore, even within the Scheme programming community, it can be
useful to distinguish procedures that are being used just to represent a
procedural abstraction from those that are used expressly to encapsulate
an environment (often to emulate what OO languages do with classes and
instances). These are conceptually different, and deserve distinct
terms.

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***

idk...@gmail.com

unread,
Sep 18, 2006, 3:49:56 AM9/18/06
to

Greetings, HL;

Thank you very much for this plain and simple explanation; I've
been attempting for more years than I can recall to wrap my neuron
around the "concept" of closures; and to finally understand it,
is very Godly!!! :)

I have always known that it was because of bad teachers and hear-say
that I had difficulty understanding what was meant by the term.

It is my firm belief that anyone who cannot explain a concept,
regardless
of subject, in simple terms also does *not* understand what they teach.

We are all teachers!

Kudos, great thanks to you.

Now, one question; when you referred to ``open procedures'' below, can
that also refer to procedures defined within procedures as Wirth
designed
in his original Pascal?

Your student.

HL wrote:
> Hi --
>
> I've just stumbled upon this explanation by Max Hailperin on the
> historical context when the term "closure" came into use.
> This is from the PLT mailing list and can found at:
> http://www.cs.utah.edu/plt/mailarch/plt-scheme-2001/msg00226.html

[snip]

Joachim Durchholz

unread,
Sep 18, 2006, 6:23:35 AM9/18/06
to
idk...@gmail.com schrieb:

> Now, one question; when you referred to ``open procedures'' below, can
> that also refer to procedures defined within procedures as Wirth
> designed in his original Pascal?

Procedures in Pascal are closures in the sense that they are always
bound to the environment in which they are lexically written.

However, they are far less useful than in Lisp or other FPLs, because
you can't create them at run-time, and because Pascal expressly forbids
such a closure from escaping its lexical context (i.e. you can't return
it to an outside caller, or assign it to any variable).
These restrictions were in effect to avoid having to store closures on
the heap. At that time, stop-the-world garbage collection was the norm
unless you were into GC research.

Regards,
Jo

Torben Ægidius Mogensen

unread,
Sep 18, 2006, 6:41:18 AM9/18/06
to
Joachim Durchholz <j...@durchholz.org> writes:

> idk...@gmail.com schrieb:
>> Now, one question; when you referred to ``open procedures'' below, can
>> that also refer to procedures defined within procedures as Wirth
>> designed in his original Pascal?
>
> Procedures in Pascal are closures in the sense that they are always
> bound to the environment in which they are lexically written.
>
> However, they are far less useful than in Lisp or other FPLs, because
> you can't create them at run-time,

How so? What makes them less run-time creatable than closures in, say,
SML?

> and because Pascal expressly forbids such a closure from escaping
> its lexical context (i.e. you can't return it to an outside caller,
> or assign it to any variable).

That is a serious limitation, I agree.

> These restrictions were in effect to avoid having to store closures
> on the heap.

Indeed. But you could get quite far within the limitations -- never
returning a closure from its context could be done by using a kind of
continuation-passing style (which would, however, quickly use up stack
space). I once wrote an 8-queens program in Pascal using explicit
success and failure continuations. Few Pascal programmers could
understand what was going on. :-)

For the interested, I have included the full text below.

Torben


program nqueens(input,output);

var
n : integer;

procedure try(x,y : integer;
function ok(x1,y1 : integer) : boolean;
procedure print;
procedure fail);

function newok(x1,y1 : integer) : boolean;
begin
newok := ok(x1,y1) and (y<>y1) and (x+y<>x1+y1) and (x-y<>x1-y1)
end;

procedure newprint;
begin
writeln(x+1:2,' ++++++++++++++++++++++':y+1,'Q++++++++++++++++++++':n-y);
print
end;

procedure newfail;
begin
try(x,y+1,ok,print,fail)
end;

begin
if x=n then begin print; fail end
else if y=n then fail
else if ok(x,y) then try(x+1,0,newok,newprint,newfail)
else newfail
end;

function ok0(x,y : integer) : boolean;
begin
ok0 := true
end;

procedure print0;
begin
writeln(' ABCDEFGHIJKLMNOPQRSTUV':n+3);
writeln
end;

procedure fail0;
begin
writeln('That''s all folks')
end;

begin
readln(n);
try(0,0,ok0,print0,fail0)
end.


Max Hailperin

unread,
Sep 18, 2006, 11:27:03 AM9/18/06
to
Barry Margolin <bar...@alum.mit.edu> writes:

> In article <86y7sik...@agora.my.domain>, HL <n...@nowhere.com> wrote:

> [quoting from me]
> > ... (When was
> > the last time you saw a procedure that hadn't been closed?)...
>
> How about almost all conventional programming languages, ...

I don't think that is true. I think what Barry has in mind is that in
most popular languages, no fancy mechanism is required to ensure that
procedures are closed (don't capture free variables from their calling
contexts) because the only free variables are global ones. However,
that doesn't make them any less closed. Consider, for example, the
following C program:

int x = 42;

int foo(){
return x;
}


int main(int argc, char **argv){
int x = 17;
return foo();
}

What exit status code is returned from main? Answer, 42, not 17. So,
the variable x, which appears free in foo, is not captured from the
calling environment in main, but rather is closed over the global
variable x.

As I said, the implementation mechanism for this is much simpler than
is needed for closures in Scheme -- but that doesn't make us any more
in need of differentiating "open" (dynamically scoped) procedures from
"closed" (lexically scoped) ones.

-max

Joachim Durchholz

unread,
Sep 18, 2006, 12:06:35 PM9/18/06
to
Torben Ægidius Mogensen schrieb:
> Joachim Durchholz <j...@durchholz.org> writes:
>
>> However, [closures] are far less useful than in Lisp or other FPLs,

>> because you can't create them at run-time,
>
> How so? What makes them less run-time creatable than closures in, say,
> SML?

For a selection of closure values, you're restricted to those that exist
in the source code.
E.g. If you have a two-parameter function foo (x, y), you can't
construct a single-parameter function foo (3, y) and pass that around.
If you have two-parameter functions foo (x, y) and bar (z, a), you can't
construct a three-parameter function foo (bar (z, a), y) and pass that
around.

I.e. what's missing are operators that can compose function values.

Regards,
Jo

Marcin 'Qrczak' Kowalczyk

unread,
Sep 18, 2006, 12:33:13 PM9/18/06
to
Followup-To: comp.lang.functional

Joachim Durchholz <j...@durchholz.org> writes:

> For a selection of closure values, you're restricted to those that
> exist in the source code.
> E.g. If you have a two-parameter function foo (x, y), you can't
> construct a single-parameter function foo (3, y) and pass that around.

This is not true; you can do that in Pascal.

You only can't return it from a function nor store it in a variable.
It must be defined "above" places where it is used, and passed via
function parameters.

Borland Pascal has an additional restriction wrt. standard Pascal:
you can't pass a local function as a function parameter at all,
you can only apply it directly. OTOH you can store functions in
variables, while you can't do that in standard Pascal.

--
__("< Marcin Kowalczyk
\__/ qrc...@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/

Barry Margolin

unread,
Sep 18, 2006, 9:09:53 PM9/18/06
to
In article <m2eju96...@max-hailperins-ibook-g4.local>,
Max Hailperin <m...@gustavus.edu> wrote:

> Barry Margolin <bar...@alum.mit.edu> writes:
>
> > In article <86y7sik...@agora.my.domain>, HL <n...@nowhere.com> wrote:
> > [quoting from me]
> > > ... (When was
> > > the last time you saw a procedure that hadn't been closed?)...
> >
> > How about almost all conventional programming languages, ...
>
> I don't think that is true. I think what Barry has in mind is that in
> most popular languages, no fancy mechanism is required to ensure that
> procedures are closed (don't capture free variables from their calling
> contexts) because the only free variables are global ones. However,
> that doesn't make them any less closed. Consider, for example, the
> following C program:
>
> int x = 42;
>
> int foo(){
> return x;
> }
>
>
> int main(int argc, char **argv){
> int x = 17;
> return foo();
> }
>
> What exit status code is returned from main? Answer, 42, not 17. So,
> the variable x, which appears free in foo, is not captured from the
> calling environment in main, but rather is closed over the global
> variable x.

That's just ordinary lexical scoping, and has nothing to do with whether
the function is closed.

> As I said, the implementation mechanism for this is much simpler than
> is needed for closures in Scheme -- but that doesn't make us any more
> in need of differentiating "open" (dynamically scoped) procedures from
> "closed" (lexically scoped) ones.

The distinction between open and closed procedures is only relevant in
languages that allow nested functions. Furthermore, what's special
about Scheme closures is that they can be RETURNED and the environment
is preserved -- i.e. they are upward funargs. Downward funargs have
existed at least since Algol.

Max Hailperin

unread,
Sep 18, 2006, 11:00:43 PM9/18/06
to
Barry Margolin <bar...@alum.mit.edu> writes:

...


> That's just ordinary lexical scoping, and has nothing to do with whether
> the function is closed.

...


> The distinction between open and closed procedures is only relevant in

> languages that allow nested functions. ...

You obviously have a strongly held definition of "whether the function
is closed" or "the distinction between open and closed procedures."
Unfortunately, our communication is impeded by the fact that your
definition differs from the one I am using. I would suggest that my
choice of definition is not arbitrary or personal, in that it rests on
a published track record of at least 36 years. If you go back and
read Joel Moses's article in the July 1970 ACM SIGSAM Bulletin(*), you
will find him giving on p. 22 an example with non-nested procedures
(not so different from my earlier C example) and then proceding to use
it as the basis to discuss on p. 25 the alternatives of "open" or
"closed" lambda expressions. (He also ties this to Landin's use of
the word "closure.") Thus, your complaint seems to be with Moses as
much as with me.

(*) Moses, Joel. "The function of FUNCTION in LISP or why the FUNARG
problem should be called the environment problem." ACM SIGSAM
Bulletin. Issue 15 (July 1970). Pages 13-27.

Torben Ægidius Mogensen

unread,
Sep 19, 2006, 5:12:07 AM9/19/06
to
Joachim Durchholz <j...@durchholz.org> writes:

> Torben Ægidius Mogensen schrieb:
>> Joachim Durchholz <j...@durchholz.org> writes:
>>
>>> However, [closures] are far less useful than in Lisp or other FPLs,
>>> because you can't create them at run-time,
>> How so? What makes them less run-time creatable than closures in,
>> say,
>> SML?
>
> For a selection of closure values, you're restricted to those that
> exist in the source code.

That is also true for SML: Any closure is a pair of code from the
source code and an environment binding free variables.

> E.g. If you have a two-parameter function foo (x, y), you can't
> construct a single-parameter function foo (3, y) and pass that around.
> If you have two-parameter functions foo (x, y) and bar (z, a), you
> can't construct a three-parameter function foo (bar (z, a), y) and
> pass that around.
>
> I.e. what's missing are operators that can compose function values.

These limitations are due to not being able to return functional
values from functions, not from lack of being able to construct the
functions. For example, you can have a function that takes two
functions and a continuation and calls the continuation with the
composition of these functions as argument (with apologies for
possible minor syntactic inaccuracies):

function compose(function f(x:integer):integer,
function g(x:integer):integer,
function k(function h(x:integer):integer):integer):integer
function fog(x:integer):integer
begin
fog := f(g(x))
end;
begin
k(fog)
end;

Torben

Anton van Straaten

unread,
Sep 22, 2006, 1:33:13 AM9/22/06
to
Max Hailperin once wrote:
>
> So anyhow, an evolutionary milestone in the development of the Lisp
> family of languages was the realizations that procedures should be
> "closed", that is, converted into a form where all the variables are
> bound rather than free. (The way this is normally done, as others
> have written in this thread, is by associating the procedure text,
> which still has free variables, with a binding environment that
> provides the bindings.)
>
> Because this was such a big deal in terms of the languages' evolution,
> Lisp hackers took to using the word "closure" rather than just
> "procedure" to emphasize that they were talking about this great new
> lexically scoped kind of procedure.

My knowledge of this history is entirely second-hand, but this
characterization seems too Lisp-specific to me. After all, Landin used
the term "closure" in his 1964 paper on the SECD machine, and even if
that usage derived from Lisp, it has become standard for functional
languages, and is even used in books such as Hankin's "Lambda Calculi: A
Guide for Computer Scientists", i.e. books about mathematical formalisms
(albeit geared towards computer scientists).

> As with so many words, it stuck, and people continued using it long
> after the distinction it was making ceased to be relevant. (When was
> the last time you saw a procedure that hadn't been closed?)

Terms often outlive the original motivation for choosing them (whether
or not that's the case here). Perhaps Murray Gell-Mann had the right
idea, coining names such as "quark" and giving them properties such as
"color". It obviates objections on the grounds of diminished relevance
of the words chosen as technical terms.

> I find this kind of anachronism endearing, just like I grinned a bit
> when I recently caught myself calling my compilers textbook the "red
> dragon book" -- a name that distinguishes it from the "green dragon
> book," which has been extinct for a decade and a half. But I would
> never consciously teach a new student to say "red dragon book" rather
> than just "dragon book." And I would never consciously teach a new
> student to say "closure" rather than just "procedure."

The difference here is that "closure" in this sense is not an extinct
term. Using the term "procedure" in the context of Scheme certainly
makes sense, but I would think that connecting it to "closure" would be
useful for students, even quite early on, since it's fairly likely that
they're going to encounter the term sooner rather than later. Nowadays,
they might encounter it in the context of Perl, Python, and Ruby, too.

Anton

Joachim Durchholz

unread,
Sep 22, 2006, 5:40:46 AM9/22/06
to
Anton van Straaten schrieb:

>
> The difference here is that "closure" in this sense is not an extinct
> term. Using the term "procedure" in the context of Scheme certainly
> makes sense, but I would think that connecting it to "closure" would be
> useful for students, even quite early on, since it's fairly likely that
> they're going to encounter the term sooner rather than later. Nowadays,
> they might encounter it in the context of Perl, Python, and Ruby, too.

Right, but it's still typical "ivory tower" terminology: the origin of
the word is obscure, doesn't allow people to embed it in a network of
established terminology, and people who need to guess the meaning (such
as when reading a text and stumbling over the word for the first time)
get no clue about its meaning.
It's ivory-tower style because this combination helps to keep outsiders
out. I find such traditions distasteful, but that's just personal
judgement; what's more relevant here is that excluding newbies is not
what most programming-language communities want. (Functional languages
seem to be prone to such terminology. "Monadic I/O" is a similar case.)

Maybe somebody has a better terminology... and uses it in a book that's
as influential as SICP... :-)

Regards,
Jo

Paul Rubin

unread,
Sep 22, 2006, 7:21:45 AM9/22/06
to
Joachim Durchholz <j...@durchholz.org> writes:
> > The difference here is that "closure" in this sense is not an
> > extinct term....

>
> Right, but it's still typical "ivory tower" terminology: the origin of
> the word is obscure, doesn't allow people to embed it in a network of
> established terminology, and people who need to guess the meaning
> (such as when reading a text and stumbling over the word for the first
> time) get no clue about its meaning.

Reminds me of Richard Feynman's story of reviewing some grade school
math books. They kept referring to "whole numbers", "counting
numbers", etc. It took him a while to figure out that they meant what
he was used to calling "integers".

Closures, like integers, -are- established terminology, whether or not
they've always been that.

Joachim Durchholz

unread,
Sep 22, 2006, 8:14:08 AM9/22/06
to
Paul Rubin schrieb:

> Closures, like integers, -are- established terminology, whether or not
> they've always been that.

Sure, but it's still a scare word.

This is very similar to recursion or monadic I/O.
* All are high-brow, non-self-explaining terms.
* All have severe implementation implications.
* All have a lot of very interesting theory associated with them.
* All are very hard to learn if starting with theory or implementation.
* All can easily be taught if starting with basic usage,
exploring implementations and borderline cases later.

Really, I don't understand why some programming language communities
hold such scare terminology so dear.
From the outside, this is perceived as an elitist attitude, so people
flock to "beginner languages" like PHP or, ten years earlier, Basic.

Don't give recursion a name, say "yes, a function is allowed to call
itself - just make sure that every invocation does some real work".
Don't give monadic I/O a name, say "functions aren't allowed to have
side effects, the code just generates a description of the effects".
Don't give closures a name, say "you can pass around an unevaluated
'expression with holes', just consider that the variables that were
defined at the place where the expression is written will be taken from
that place, not from the place where the thing will be evaluated".

You don't need that special terminology. Except when you're talking
about implementation, or doing formal semantics.
Programmers *should* know about implementation, of course (if only to
get a realistic "feel" for the efficiency of the code they're writing),
but this can come months after they have learned to use these concepts.
(You learned to multiply by hand, but understanding how that algorithm
works came much, much later if at all, right?)

Regards,
Jo

Philippa Cowderoy

unread,
Sep 22, 2006, 9:08:40 AM9/22/06
to
On Fri, 22 Sep 2006, Joachim Durchholz wrote:

> Don't give monadic I/O a name, say "functions aren't allowed to have side
> effects, the code just generates a description of the effects".

So what do we call the Monad typeclass, which can and will show up in
types and type errors?

--
fli...@flippac.org

Ivanova is always right.
I will listen to Ivanova.
I will not ignore Ivanova's recomendations.
Ivanova is God.
And, if this ever happens again, Ivanova will personally rip your lungs out!

Tomasz Zielonka

unread,
Sep 22, 2006, 9:11:59 AM9/22/06
to
[I am a bit surprised that we are discussing this at all]

Joachim Durchholz wrote:
> Really, I don't understand why some programming language communities
> hold such scare terminology so dear.

It's not scary when you get used to it.

> From the outside, this is perceived as an elitist attitude, so people
> flock to "beginner languages" like PHP or, ten years earlier, Basic.

Now those are scare words! ;-)

> Don't give monadic I/O a name, say "functions aren't allowed to have
> side effects, the code just generates a description of the effects".

I can see that:

return :: SomethingThatWorksAroundTheLackOfSideEffectsIn...
LanguagesWithoutSideEffectsStopErmmmIsFunctionalAScaryWord...
QuestionMarkNoQuestionMarkOKStopSoFunctionalLanguages...
ByGeneratingSomethingLikeADescription...
OfTheEffectsStopByTheWayItHasThePropertiesOfACertain...
MathematicalConstructWhichWeWontNameHereBecause...
WeDontWantToScareNewbiesButIfYouAreInterestedItIs...
AnAnagramOfNomadStop m => a -> m a

(>>=) :: SomethingThatWorksAroundTheLackOfSideEffectsIn...
...

No, this is unacceptable. We need to have short descriptions for these
things. That's how the language and knowledge works. You probably
underestimate how much scare words you use yourself. Haven't you ever
talked about programming when non-programmers were overhearing nearby -
how much do you think they understood? It never to you happened that
someone said "guys, wow, I have completely no idea what you are
talking about", and you thought, "hey, these are just the basics,
we haven't started to talk about monads yet".

Also, there may be other things that have similar goals as monads, but
are fundamentally different in some aspects. How would you know that the
other person is not talking about them?

> Don't give closures a name, say "you can pass around an unevaluated
> 'expression with holes', just consider that the variables that were
> defined at the place where the expression is written will be taken from
> that place, not from the place where the thing will be evaluated".

What holes? I think your description of closures is misleading. And
besides, we wouldn't be talking about closures if more mainstream
languages supported them. I guess the most popular statement with
"closures" in it is "I wish this language supported closures.".

And BTW, what do you mean by "unevaluated", "expression", "variables",
"defined", "written", "taken", "place"?

Best regards
Tomasz

Max Hailperin

unread,
Sep 22, 2006, 10:32:49 AM9/22/06
to
Anton van Straaten <an...@appsolutions.com> writes:

> Max Hailperin once wrote: [an off the cuff pseudo history]

> My knowledge of this history is entirely second-hand, but this
> characterization seems too Lisp-specific to me. After all, Landin

> used the term "closure" in his 1964 paper on the SECD machine,...

Mea culpa. Looking more closely at the actual historical record, I
realized that I overstated the MIT (= Lisp) end of things and
understated Landin's role. -max

David Hopwood

unread,
Sep 22, 2006, 11:13:32 AM9/22/06
to
Joachim Durchholz wrote:
> Don't give recursion a name, say "yes, a function is allowed to call
> itself - just make sure that every invocation does some real work".
> Don't give monadic I/O a name, say "functions aren't allowed to have
> side effects, the code just generates a description of the effects".
> Don't give closures a name, say "you can pass around an unevaluated
> 'expression with holes', just consider that the variables that were
> defined at the place where the expression is written will be taken from
> that place, not from the place where the thing will be evaluated".
>
> You don't need that special terminology.

Yes, we do. We need concise names for concepts in order to even think about
those concepts, never mind to explain them or use them.

--
David Hopwood <david.nosp...@blueyonder.co.uk>

Andru Luvisi

unread,
Sep 22, 2006, 6:38:04 PM9/22/06
to
HL> As with so many words, it stuck, and people continued using it
HL> long after the distinction it was making ceased to be
HL> relevant. (When was the last time you saw a procedure that
HL> hadn't been closed?)

In Ruby, the instance_eval method allows you to run a block (aka
procedure) in the context of a particular object (an environment of
sorts). This can be used to create domain specific languages by
letting the client hand you a block to execute and then executing the
block in an object that has a bunch of useful methods predefined.

Ruby blocks aren't open in the way that the original Lisp 1.5 lambda
expressions were, but they aren't closed in the way that Scheme
closures are either.

A significant amount of the Lisp usage out there is done with Emacs
lisp, which is dynamically scoped and has "open" functions.

Perl has both dynamic and lexical scoping. Procedures are closed with
respect to lexical variables, and open with respect to dynamically
scoped variables.

I don't use tcl, but last I heard it was dynamically scoped and
procedures were open.

To answer the question of when I last saw a procedure that wasn't
closed: Quite recently.

Andru
--
Andru Luvisi

Quote Of The Moment:
Heisenberg may have been here.

Marcin 'Qrczak' Kowalczyk

unread,
Sep 22, 2006, 7:02:17 PM9/22/06
to
Followup-To: comp.lang.functional

Andru Luvisi <luv...@andru.sonoma.edu> writes:

> In Ruby, the instance_eval method allows you to run a block
> (aka procedure) in the context of a particular object
> (an environment of sorts).

This is similar to passing "self" as an implicit parameter.
Maybe even equivalent.

> Perl has both dynamic and lexical scoping.

No, it has only lexical scoping.

If you meant 'local', it just temporarily changes the value
of a variable, and restores it when the current scope returns.

Ray Dillinger

unread,
Sep 22, 2006, 7:20:01 PM9/22/06
to
Anton van Straaten wrote:

> Terms often outlive the original motivation for choosing them (whether
> or not that's the case here). Perhaps Murray Gell-Mann had the right
> idea, coining names such as "quark" and giving them properties such as
> "color". It obviates objections on the grounds of diminished relevance
> of the words chosen as technical terms.

As far as I know, he was poking fun at the postadolesent-mystics'
near-universal appropriation of the physicist's word "energy" by
appropriating what should properly have been one of their words,
"charmed", as a property of quarks. I don't know whether he was
making similar jokes with "strangeness" and "color" and so on,
but it doesn't seem too unlikely.

Bear

Joachim Durchholz

unread,
Sep 23, 2006, 7:05:37 AM9/23/06
to
Tomasz Zielonka schrieb:

> [I am a bit surprised that we are discussing this at all]
>
> Joachim Durchholz wrote:
>> Really, I don't understand why some programming language communities
>> hold such scare terminology so dear.
>
> It's not scary when you get used to it.

That holds for everything scary...

>> Don't give monadic I/O a name, say "functions aren't allowed to have
>> side effects, the code just generates a description of the effects".
>

> No, this is unacceptable. We need to have short descriptions for these
> things.

OK, I can agree with that.

Actually, I wouldn't want to replace recursion with "function that may
call itself" in all texts.
On the other hand, you don't *need* to use the term when teaching a
language. Just say "oh, and functions may call themselves", with the
usual caveats. You don't *need* the terminology until you're really into
fixed-point theory (or when comparing languages).
Well, you also need it in a functional context when explaining how to do
loops. But why call it "recursion"? Most of the time, I see references
like "have the function call itself recursively" - that's just silly,
say "have the function call itself".

"Monads" are more on point. You can say "heterogenous associativity",
and most programmers will have a vague idea of what it's all about. (The
term is a bit narrower than what monads really are, I think, but that's
what those monads I have seen are really used for.)

A really silly case is "monadic I/O". That's just like characterizing
multiplication as "associative number combination" - it's true, and
captures one property of the whole mechanism, but certainly not the most
relevant aspect.

Coming back to the main topic, "closure".
Why not call it "lexical binding"? If all names are bound by lexical
rules (i.e. when deep binding is applied), then the result is a closure.
(At least that's how I understand the term.)
Since lexical binding is the default anyway (shallow binding doesn't
scale well, so it should be used very, very sparingly if at all), then
there's no need to differentiate; the things that get passed around are
expressions anyway.

> That's how the language and knowledge works. You probably
> underestimate how much scare words you use yourself. Haven't you ever
> talked about programming when non-programmers were overhearing nearby -
> how much do you think they understood? It never to you happened that
> someone said "guys, wow, I have completely no idea what you are
> talking about",

Sure.
But usually I can change my language so that nonprogrammers know what
I'm talking about. I lose a lot of precision, but that would be lost on
nonprogrammers anyway.

> and you thought, "hey, these are just the basics,
> we haven't started to talk about monads yet".

That's *exactly* the point I'm trying to make!

Monads are really simple. "Foo is a monad" is a statement of the same
quality as "bar is associative" - interesting, but certainly not
complicated.
People think that monads are something complicated and arcane, because
they are from Category Theory which is also seen as complicated and arcane.

> What holes? I think your description of closures is misleading.

Well, yes. It seems that I still have problems talking clearly about
them, after 20+ years of programming and (vaguely) knowing what they are.
I think that's due to the fact that I usually don't need that
terminology. I need terminology for lazy evaluation, for unevaluated
expressions, for locality and such, even when talking about Haskell or
other functional languages - but I don't need terminology for closures.

Frankly, I don't care whether an expression is closed or open. Insisting
that a and b are unbound in a+b but bound in \a,b:a+b is just syntactic
silliness: either way, a and b still need to be bound before the
addition can be executed.
Well, this holds only for programmers. For language implementors, there
is indeed a difference. Maybe Lispers need to differentiate that way
because they actually get to see open expressions, so stating that an
expression is closed (and hence can be transported to different
environments without changing its semantics) is an important bit of
information.

> And
> besides, we wouldn't be talking about closures if more mainstream
> languages supported them. I guess the most popular statement with
> "closures" in it is "I wish this language supported closures.".

Most of the time, people with this sentiment say "I wish this language
had higher-order functions".
This gets misunderstood - C has HOFs after all :-)
What they really want is a way to pass "expressions with holes" around.
I.e. a way to write an expression where some values are left
unspecified, and have other parts of the program fill them in and
evaluate the thing. Closures are just one way to provide that mechanism.

Regards,
Jo

Benjamin Franksen

unread,
Sep 23, 2006, 6:18:50 PM9/23/06
to
Joachim Durchholz wrote:
> Tomasz Zielonka schrieb:
>> [I am a bit surprised that we are discussing this at all]
>>
>> Joachim Durchholz wrote:
>>> Really, I don't understand why some programming language communities
>>> hold such scare terminology so dear.
>>> Don't give monadic I/O a name, say "functions aren't allowed to have
>>> side effects, the code just generates a description of the effects".
>>
>> No, this is unacceptable. We need to have short descriptions for these
>> things.
>
> [...]

>
> "Monads" are more on point. You can say "heterogenous associativity",
> and most programmers will have a vague idea of what it's all about. (The
> term is a bit narrower than what monads really are, I think, but that's
> what those monads I have seen are really used for.)
>
> A really silly case is "monadic I/O". That's just like characterizing
> multiplication as "associative number combination" - it's true, and
> captures one property of the whole mechanism, but certainly not the most
> relevant aspect.

I have to disagree. IMO it /is/ the most relevant aspect, as soon as you
take the representation of 'primitive' I/O actions as an abstract data type
for granted.

Why? First note that the primitive action values would be (almost) useless
without a way to sequence them together to form programs.

The astonishing fact is that the monad combinators and the corresponding
laws are /exactly/ what is required to precisely capture the essence of how
sequencing works in any imperative programming language. Monadic I/O simply
recognizes this fact and provides the basic sequencing operation not as a
language construct, as in imperative languages, but as /functions/, namely
the monadic 'bind' (>>=) and 'return' functions. This is of course possible
only after you recognize actions as (first class) values.

As to your "multiplication as "associative number combination": Sure,
associativity does not capture the essence of what multiplication of
numbers is. For instance, there is commutatitivity, neutral elements,
distribution laws (referring to yet another function named "addition") and
don't forget the interaction with ordering. However, as soon as you take
all these laws together you /can/ precisely capture the essence of
what "multiplication of numbers" really is.

Compare this to I/O and "monadicity": there is nothing missing here. Can you
name /any/ additional law (maybe involving additional primitive
combinators) which are necessary to capture how imperative programms are
constructed from 'I/O actions' (aka 'statements')?

Cheers,
Ben

Joachim Durchholz

unread,
Sep 24, 2006, 8:22:34 AM9/24/06
to
Benjamin Franksen schrieb:

> Joachim Durchholz wrote:
>> A really silly case is "monadic I/O". That's just like characterizing
>> multiplication as "associative number combination" - it's true, and
>> captures one property of the whole mechanism, but certainly not the most
>> relevant aspect.
>
> I have to disagree. IMO it /is/ the most relevant aspect, as soon as you
> take the representation of 'primitive' I/O actions as an abstract data type
> for granted.
>
> Why? First note that the primitive action values would be (almost) useless
> without a way to sequence them together to form programs.
>
> The astonishing fact is that the monad combinators and the corresponding
> laws are /exactly/ what is required to precisely capture the essence of how
> sequencing works in any imperative programming language.

Sure. But I/O is more than just sequencing - and that isn't surprising:
if it were otherwise, then there would be no interesting monads beyond IO.

A better approximation would be to say "a monad is about stringing
together type-heterogenous things, and that stringing-together is
associative". I say "approximation" because I'm sure enough that
everything described in the definition above is a monad, but I'm not
sure that the definition covers everything that is a monad.

> Monadic I/O simply recognizes this fact and provides the basic
> sequencing operation not as a language construct, as in imperative
> languages, but as /functions/, namely the monadic 'bind' (>>=) and
> 'return' functions. This is of course possible only after you
> recognize actions as (first class) values.
>
> As to your "multiplication as "associative number combination": Sure,
> associativity does not capture the essence of what multiplication of
> numbers is. For instance, there is commutatitivity, neutral
> elements, distribution laws (referring to yet another function named
> "addition") and don't forget the interaction with ordering.

I couldn't have said that better.

> However, as soon as you take all these laws together you /can/
> precisely capture the essence of what "multiplication of numbers"
> really is.

Sure. Still, you wouldn't characterize "multiplication of numbers" as
"associative number combination", wouldn't you?

My hypothesis is that calling Haskell's ways of doing I/O "monadic I/O"
has the same kind of terminological mismatch, i.e. it names the concept
after just one of several important properties.

> Compare this to I/O and "monadicity": there is nothing missing here.
> Can you name /any/ additional law (maybe involving additional
> primitive combinators) which are necessary to capture how imperative
> programms are constructed from 'I/O actions'

That depends on what aspects of I/O you want to capture in the terminology.

> 'I/O actions' (aka 'statements')?

That's still very different things. Statements that don't involve IO can
usually be easily mapped to purely functional code. Sometimes it may be
helpful to apply the State monad, but even that is purely functional.

You have to step outside that and use the IO monad only if you deal with
stateful entities that exist outside the Haskell program. Oh, and
occasionally for debugging, but I'd like to keep *that* can of worms
closed for the moment :-)

Regards,
Jo

Philippa Cowderoy

unread,
Sep 24, 2006, 1:08:01 PM9/24/06
to
On Sat, 23 Sep 2006, Joachim Durchholz wrote:

> "Monads" are more on point. You can say "heterogenous associativity", and most
> programmers will have a vague idea of what it's all about. (The term is a bit
> narrower than what monads really are, I think, but that's what those monads I
> have seen are really used for.)
>

The fact that in functional programming we build them around an
endofunctor is pretty important, especially in a typed context. The
typical examples of a monad in haskell involve more than just heterogenous
associativity, they wouldn't be as useful otherwise. Of course, the
numerous monads that could be built around an identity type function
instead of a type constructor don't exhibit this - the fact we're taking
the "obvious" monads within the restrictions of our languages is relevant.

--
fli...@flippac.org

Society does not owe people jobs.
Society owes it to itself to find people jobs.

Joachim Durchholz

unread,
Sep 24, 2006, 2:54:14 PM9/24/06
to
Philippa Cowderoy schrieb:

> On Sat, 23 Sep 2006, Joachim Durchholz wrote:
>
>> "Monads" are more on point. You can say "heterogenous associativity", and most
>> programmers will have a vague idea of what it's all about. (The term is a bit
>> narrower than what monads really are, I think, but that's what those monads I
>> have seen are really used for.)
>
> The fact that in functional programming we build them around an
> endofunctor is pretty important, especially in a typed context.

I'm lost now - what's an endofunctor?
My knowledge of Category Theory is that arrows look very much like
relations and not much more, so please be patient and stick with simple
words... ;-)

> The typical examples of a monad in haskell involve more than just
> heterogenous associativity, they wouldn't be as useful otherwise.

Hmm... which monads are non-associative?
I think those standard monads (IO, Exception, State) are, but I may be
wrong about that, too (particularly for IO, where I'm ignorant of too
many details).

> Of course, the numerous monads that could be built around an identity
> type function instead of a type constructor don't exhibit this

Er - an entirely different kind of monads, too?

> - the fact we're taking the "obvious" monads within the restrictions
> of our languages is relevant.

I'm probably missing something here, but I do agree that the "obvious"
monads have pre-determined the views of many FPers. I have seen
knowledgeable people say that monads are about sequencing actions, and
state that even for the List monad.

Regards,
Jo

Tomasz Zielonka

unread,
Sep 24, 2006, 3:15:23 PM9/24/06
to
Joachim Durchholz wrote:
>> The typical examples of a monad in haskell involve more than just
>> heterogenous associativity, they wouldn't be as useful otherwise.
>
> Hmm... which monads are non-associative?

What she said doesn't imply that there are non-associative monads. There
aren't, by definition. IIUC, it's just that for a particular monad to be
useful it has to provide some other combinators besides return and
(>>=), preferably with some associated laws. For example, the State
monad has 'get' and 'put'.

> I have seen knowledgeable people say that monads are about sequencing
> actions, and state that even for the List monad.

I wouldn't say they are wrong - it's just that in the List monad a
single sequence of actions may have an arbitrary number of results.
That's why sometimes it is also called non-determinism monad.

Best regards
Tomasz

Philippa Cowderoy

unread,
Sep 24, 2006, 3:22:06 PM9/24/06
to
On Sun, 24 Sep 2006, Joachim Durchholz wrote:

> Philippa Cowderoy schrieb:
> > On Sat, 23 Sep 2006, Joachim Durchholz wrote:
> >
> > > "Monads" are more on point. You can say "heterogenous associativity", and
> > > most
> > > programmers will have a vague idea of what it's all about. (The term is a
> > > bit
> > > narrower than what monads really are, I think, but that's what those
> > > monads I
> > > have seen are really used for.)
> >
> > The fact that in functional programming we build them around an endofunctor
> > is pretty important, especially in a typed context.
>
> I'm lost now - what's an endofunctor?
> My knowledge of Category Theory is that arrows look very much like relations
> and not much more, so please be patient and stick with simple words... ;-)
>

It's a functor that maps between a category and itself (cf endofunction).
In Haskell, functors are normally type constructors with an associated
fmap function (for monads, liftM - it's something of an accident that
Monad isn't a subclass of Functor) - and they're all endofunctors, turning
Haskell types to Haskell types.

My own CT knowledge isn't brilliant, I've spent a while getting some basic
intuitions down though - it's a nice playground if you're inclined to lose
yourself in various flavours of metaness, and there're some cute patterns
to play with.

> > The typical examples of a monad in haskell involve more than just
> > heterogenous associativity, they wouldn't be as useful otherwise.
>
> Hmm... which monads are non-associative?

Not what I meant. Extra structure, not losing associativity.

> > Of course, the numerous monads that could be built around an identity
> > type function instead of a type constructor don't exhibit this
>
> Er - an entirely different kind of monads, too?
>

No, although a new-to-Haskellers flavour - you can't really define the
identity monad properly in Haskell, whereas if you could declare a Monad
instance around an identity type function/type constructor you'd be able
to. Or a variant where >>= gives eager sequencing, for example.

> > - the fact we're taking the "obvious" monads within the restrictions
> > of our languages is relevant.
>
> I'm probably missing something here, but I do agree that the "obvious" monads
> have pre-determined the views of many FPers. I have seen knowledgeable people
> say that monads are about sequencing actions, and state that even for the List
> monad.
>

Yes. The way I normally put it is that the monad structure supports a
notion of sequencing (whether it's really used or not). But we also make
use of the type constructors involved, which're entirely an accident of
our choice of category and our need to stay in it. The non-obvious monads
I'm referring to are all the other things that fit the CT definition when
you look at them from the right angle but can't be made instances of the
Monad typeclass.

--
fli...@flippac.org

Performance anxiety leads to premature optimisation

Philippa Cowderoy

unread,
Sep 24, 2006, 3:40:49 PM9/24/06
to
On Sun, 24 Sep 2006, Philippa Cowderoy wrote:

> The fact that in functional programming we build them around an
> endofunctor is pretty important, especially in a typed context.

I should perhaps point out here that all monads are endofunctors plus
extra structure: it's the category representing Haskell (or your preferred
language) code that makes things interesting. There are also times when it
would be nice to be able to define monads on categories smaller than "any
haskell value" - for example, the category of values belonging to types in
some type class.

--
fli...@flippac.org

There is no magic bullet. There are, however, plenty of bullets that
magically home in on feet when not used in exactly the right circumstances.

Anton van Straaten

unread,
Sep 26, 2006, 11:10:35 AM9/26/06
to
Joachim Durchholz wrote:
> Paul Rubin schrieb:
>
>> Closures, like integers, -are- established terminology, whether or not
>> they've always been that.
>
>
> Sure, but it's still a scare word.

Someone who is scared by such a word is too easily scared, and should
consider giving up software work to take up knitting instead.

But wait: knitting involves perling, which sounds scary!

Is there no escape from scary terminology?

Perhaps we should do what a certain deity is claimed to have done:
first, we'll advertise on monster.com for a guy named Adam, and we'll
hire the first one that comes along. Then, we'll bring unto Adam each
of the the abstractions we need names for, to see what he would call
them. And whatsoever Adam calls every abstraction, that will be the
name thereof.

We'll just need to ask our Adam not to come up with any scary names, and
stick to cute, warm, fuzzy ones. Problem solved.

Anton

Raffael Cavallaro

unread,
Sep 27, 2006, 1:42:31 AM9/27/06
to
On 2006-09-26 11:10:35 -0400, Anton van Straaten <an...@appsolutions.com> said:

> We'll just need to ask our Adam not to come up with any scary names,
> and stick to cute, warm, fuzzy ones. Problem solved.

thank you for providing some closure on this subject.

- sorry, couldn't resist ;^)

Joachim Durchholz

unread,
Sep 27, 2006, 8:10:52 AM9/27/06
to
Warning: this post contains lengthy rants. Anton's writing, while
amusing in parts, hit a nerve.

Anton van Straaten schrieb:


> Joachim Durchholz wrote:
>> Paul Rubin schrieb:
>>
>>> Closures, like integers, -are- established terminology, whether or not
>>> they've always been that.
>>
>> Sure, but it's still a scare word.
>
> Someone who is scared by such a word is too easily scared,

"Too easily scared" for what?
Too easily scared for being a competent programmer? Too easily scared
for maintaining and document code?
Sorry, this doesn't make much sense, unless you *want* to drive away
people who don't fit your description exactly. It may be nice to be part
of a gung-ho scared-by-nothing group, but that isn't going to broaden
the base for any programming language.
I'd prefer a language that is well-designed *and* attracts the clueless
masses. Imagine the quality of the libraries that such a language would
need to have - they would have to be really, really foolproof, because
there will be enough fools among its users! (PHP already fits the
"foolproof" part of the description. I think that's a large part of its
popularity, besides being the language to offer the right promises at
the right time.)

> and should consider giving up software work to take up knitting
> instead.

Well, I could have stuck with a more dry terminology, such as
"unfamiliar terms".
We'd be missing a witty if beside-the-point response then.

> Is there no escape from scary terminology?

Yes, there is. Jokes aside, it's often enough possible to avoid
introducing new terminology, simply by shifting the focus of the
presentation a little bit.
Of course, thinking up good metaphors and is hard, and may not be the
primary interest or even competence of everybody. Making fun of pleas in
this direction is far easier.
On the other hand, some people actually don't like to have a broader
user base for their favorite programming language. They don't want to
deal with newbies; besides, building software for general use has too
many additional design constraints for their capacities, and it doesn't
help when applying for research grants anyway.
Just don't whine if your ivory tower language never makes it into the
mainstream...

</rant>

Sorry, and thanks for listening.

Regards,
Jo

Anton van Straaten

unread,
Sep 27, 2006, 6:00:30 PM9/27/06
to
Joachim Durchholz wrote:
> Warning: this post contains lengthy rants. Anton's writing, while
> amusing in parts, hit a nerve.
>
> Anton van Straaten schrieb:
>
>> Joachim Durchholz wrote:
>>
>>> Paul Rubin schrieb:
>>>
>>>> Closures, like integers, -are- established terminology, whether or not
>>>> they've always been that.
>>>
>>>
>>> Sure, but it's still a scare word.
>>
>>
>> Someone who is scared by such a word is too easily scared,
>
>
> "Too easily scared" for what?
> Too easily scared for being a competent programmer? Too easily scared
> for maintaining and document code?

Certainly too easily scared to work on code which makes use of closures.
Unless you want to argue that the concept of closures should be
eliminated from programming languages, the concept requires a term, to
support communication and even reasoning.

In an earlier message, you proposed "lexical binding" instead of
"closure". In a parallel universe where "lexical binding" was the
terminology in use, though, someone with the parallel-universe name of
Joacholz Durchhim could come along and complain, with equal
(in)validity, that "lexical binding" is a scare term. The fact is that
most terms, especially for non-trivial concepts, are almost entirely
arbitrary.

In the case of the term "closure", you haven't satisfactorily explained
what makes it a scare word, compared to any other word for the same
concept. It's not as though we're talking about "lambda", which may
trigger a more specific fear of terminology, hellenologophobia.

Actually, it seems to me that the most substantial concern you've raised
is that "closure" could encourage the common error of trying to derive
too much meaning from the term itself, and forgetting that it's just an
ultimately arbitrary term, like any other. There's an explanation for
why it's called "closure", but the term has a meaning which does not
depend solely on that explanation, regardless of the overlap. The term
means what it does because that's what it's defined to mean.

Using a more arbitrary term could resolve this. *Avoiding* a term only
makes sense if you plan to avoid the concept, too.

> Sorry, this doesn't make much sense, unless you *want* to drive away
> people who don't fit your description exactly.

Someone who doesn't recognize that specific concepts require specific
terms might be driven away, but in most contexts, the solution to that
is not to avoid the terminology. The same goes for someone who is
afraid of learning. Avoiding the terminology wouldn't solve the real
problem here.

> Well, I could have stuck with a more dry terminology, such as
> "unfamiliar terms".

If you'd said that, my critique would have been slightly different, but
not that much. I don't see that "scare word" is synonymous with
"unfamiliar term". In fact, "scare word" is more often used in the
opposite sense: for a word whose meaning is understood, but feared.
"Terrorism" is a scare word, but it has that quality because people are
familiar with it, and understand what it means.

All terms are unfamiliar until you learn what they mean. A big purpose
of books on technical subjects, such as the one which inspired this
thread, is to introduce you to the extant terminology of the field in
question, so that you can understand other material and communicate with
other people in that field.

> We'd be missing a witty if beside-the-point response then.

I believe that my response was entirely on point. However, I concede
that some may have found its point obscured by an attempt at humor.

>> Is there no escape from scary terminology?
>
>
> Yes, there is. Jokes aside, it's often enough possible to avoid
> introducing new terminology, simply by shifting the focus of the
> presentation a little bit.

But what context are you thinking of? Introductions to programming for
the "clueless masses" that you referred to? Sure, in that context,
avoid new terminology and non-trivial concepts by all means, where
practical, at least until your masses have gained enough cluefulness to
want to move beyond the level of complete beginner. But this thread
wasn't originally discussing a book on that level.

In any case, any decent programming text has been carefully designed to
introduce terminology in a disciplined and appropriate way, so already
follows your advice to the extent considered appropriate by the authors.

But at some point, anyone who is going to go beyond minor dabbling is
going to need to be able to use the terminology of the field in
question. This answers your earlier question of "why some programming
language communities hold such scare terminology so dear." The answer
(once the unsupportable use of the word "scare" has been removed) is
that the terminology serves a valuable purpose for abstraction,
communication, compression, and reasoning, as it does in any human activity.

To come back to the point that spawned this thread, the decision to use
the term "procedure" in a book like "Concrete Abstractions" is perfectly
reasonable, but I think that the readership as a whole would be better
served if somewhere, the connection between the procedures found in
Scheme and the term "closure" was mentioned, because as has been pointed
out, the term is ubiquitous, used across languages and formalisms, with
a history going back to at least the 1960s for the sense we're
discussing. "Procedure" may be considered roughly synonymous with
"closure" in the context of Scheme, but that's not the case in many
other languages.

> On the other hand, some people actually don't like to have a broader
> user base for their favorite programming language. They don't want to
> deal with newbies; besides, building software for general use has too
> many additional design constraints for their capacities, and it doesn't
> help when applying for research grants anyway.
> Just don't whine if your ivory tower language never makes it into the
> mainstream...

You seem to be conducting an entirely different discussion here, with
your own ideological[*] agenda and set of assumptions which I don't
share. I simply think that a number of your points about terminology
are unrealistic.

Anton

[*] scare word.

Joachim Durchholz

unread,
Sep 28, 2006, 4:53:36 AM9/28/06
to
Anton van Straaten schrieb:

>
> In an earlier message, you proposed "lexical binding" instead of
> "closure". In a parallel universe where "lexical binding" was the
> terminology in use, though, someone with the parallel-universe name of
> Joacholz Durchhim could come along and complain, with equal
> (in)validity, that "lexical binding" is a scare term.

How am I supposed to answer to that - calling you "Straaton van Anten"
in return or what?
I'm rather dropping out of this silliness. You're just interested in
shooting down, not building up, and trying to be constructive in the
face of this kind of opposition is a waste of everybody's time anyway.

-Jo

Joachim Durchholz

unread,
Sep 28, 2006, 6:01:34 AM9/28/06
to
Joachim Durchholz schrieb:

> Don't give closures a name, say "you can pass around an unevaluated
> 'expression with holes', just consider that the variables that were
> defined at the place where the expression is written will be taken from
> that place, not from the place where the thing will be evaluated".

That is, of course, an overly verbose and still quite inexact (even
partially wrong) description of what a closure is. It highlights the
difference between a closure and something that takes some definitions
from the context where it's evaluated (what's the opposite of "closure"?
"openure"?)
However, other languages have used words that do have everyday
connotations, at least for newbie programmers. Smalltalk says "block".
In Haskell, the concept doesn't even have (or need) a name, it's all
expressions (in various states of evaluation, which doesn't affect the
semantics because evaluation is lazy anyway); the closest thing with a
name would be an "unnamed function" (a "lambda" in Lisp terms). Eiffel
calls them "agents" (an example for a term that's good in one aspect -
easy to grasp - but not so good in another one - uniqueness).

I think the difference between "scary" and "friendly" is whether the
term has useful everyday connotations.
For "block", it works since everybody knows what a block is (something
that you build stuff from), and it works even better if the student had
exposure to the term "block-structured language" before.
For "unnamed function", it works because every programmer knows what a
function is (even if he started with Basic).
For "closure", it doesn't work, at least for the average programmer.
Somebody who is into language implementation will know about binding
strategies, and in this context, "closure" has enough connotations to be
useful. So this term is good for language designers, compiler courses,
considerate language feature comparisons, and such - but that's stuff
for the fifth semester and above, not for introductory courses!

And it's just that I think that to attract more programmers to a
language, the terminology must be easy to grasp for freshmen - after
all, when learning a truly new concept, we're all freshmen.

Regards,
Jo

Jens Axel Søgaard

unread,
Sep 28, 2006, 6:58:58 AM9/28/06
to
Joachim Durchholz wrote:

> I think the difference between "scary" and "friendly" is whether the
> term has useful everyday connotations.

> For "block", it works since everybody knows what a block is (something
> that you build stuff from), and it works even better if the student had
> exposure to the term "block-structured language" before.

> For "unnamed function", it works because every programmer knows what a
> function is (even if he started with Basic).

> For "closure", it doesn't work, at least for the average programmer.
> Somebody who is into language implementation will know about binding
> strategies, and in this context, "closure" has enough connotations to be
> useful. So this term is good for language designers, compiler courses,
> considerate language feature comparisons, and such - but that's stuff
> for the fifth semester and above, not for introductory courses!
>
> And it's just that I think that to attract more programmers to a
> language, the terminology must be easy to grasp for freshmen - after
> all, when learning a truly new concept, we're all freshmen.

There are pros and cons of using the same words for everyday terms
and mathematical terms. Some students transfer too much old knowledge
into the new domain.

A classical example is "apples or oranges". In everyday language
it is an either-or in math an inclusive-or.

Words like "function", "relation", "statement" and others have very
precise meanings in mathematics,

In the same way you have to get used to the mathematical usage
of adjectives. Sometimes adding a "adjective foo" is not a "foo".

Another strange "friendly" usage is:

f is differentiable in 3
f is not differentiable

both statements can be true at the same time.

Choosing terms for concepts is hard. The term chosen must have
some connotation in the real word in order to easy to remember,
but changing the meaning of everyday words is potentially
more confusing than choosing abstract words like "closure".
It depends of course on the specific alternative word.

--
Jens Axel Søgaard

Joachim Durchholz

unread,
Sep 28, 2006, 9:07:51 AM9/28/06
to
Torben Ægidius Mogensen schrieb:
> Joachim Durchholz <j...@durchholz.org> writes:
>
>> Torben Ægidius Mogensen schrieb:
>>> Joachim Durchholz <j...@durchholz.org> writes:
>>>
>>>> However, [closures] are far less useful than in Lisp or other FPLs,
>>>> because you can't create them at run-time,
>>> How so? What makes them less run-time creatable than closures in,
>>> say,
>>> SML?
>> For a selection of closure values, you're restricted to those that
>> exist in the source code.
>
> That is also true for SML: Any closure is a pair of code from the
> source code and an environment binding free variables.

Yes, but the code need not be a function, it can be any expression. In
particular one that's inline in the normal flow of the logic.

> These limitations are due to not being able to return functional
> values from functions, not from lack of being able to construct the
> functions.

I agree with the first half of that.
I can see the view for the second part. My view of "value" is something
that can be passed to callers; in that sense, Pascal doesn't offer a way
to construct function values (well, it doesn't even really have them).

Anyway. I think we can agree that Pascal's higher-order function
facilities are far too restrictive to make it useful as a functional
programming language :-)

Regards,
Jo

Andreas Rossberg

unread,
Sep 28, 2006, 12:37:14 PM9/28/06
to
Joachim Durchholz wrote:
>>
>> That is also true for SML: Any closure is a pair of code from the
>> source code and an environment binding free variables.
>
> Yes, but the code need not be a function, it can be any expression. In
> particular one that's inline in the normal flow of the logic.

Unless you specifically talk about lazy languages, that's simply wrong.
Neglecting realisations of toplevel decs ("main"), every closure and
every piece of compiled code corresponds to a function that is
explicitly written, syntactically as a function expression or
definition, in the source program. There is no code representing
anything else but explicit function bodies.

NB: I remember that I already had the very same discussion with you some
time ago. I hope you believe me this time. ;-)

Cheers,
- Andreas

Anton van Straaten

unread,
Sep 28, 2006, 1:04:24 PM9/28/06
to
Joachim Durchholz wrote:
> Anton van Straaten schrieb:
>
>>
>> In an earlier message, you proposed "lexical binding" instead of
>> "closure". In a parallel universe where "lexical binding" was the
>> terminology in use, though, someone with the parallel-universe name of
>> Joacholz Durchhim could come along and complain, with equal
>> (in)validity, that "lexical binding" is a scare term.
>
>
> How am I supposed to answer to that - calling you "Straaton van Anten"
> in return or what?

I was kidding around. (Traditionally, people in parallel universes have
some characteristic that distinguishes them from their alternate
selves.) Sorry if you took it personally.

Anton

Ray Dillinger

unread,
Sep 28, 2006, 6:19:19 PM9/28/06
to
Andreas Rossberg wrote:
> Joachim Durchholz wrote:

>> Yes, but the code need not be a function, it can be any expression. In
>> particular one that's inline in the normal flow of the logic.

> Unless you specifically talk about lazy languages, that's simply wrong.
> Neglecting realisations of toplevel decs ("main"), every closure and
> every piece of compiled code corresponds to a function that is
> explicitly written, syntactically as a function expression or
> definition, in the source program. There is no code representing
> anything else but explicit function bodies.

I've been thinking as I read this thread about "opening" closures
and/or "reclosing" them under the bindings of a different environment
than that in which they were created.

I cannot think of a sane reason why anyone would do this in the
design of new working code, but it is interesting at least to
consider from the perspective of teaching in language-design, or
for building emulation layers for running one or more of LISP's
Elder Dialects.

Bear

Anton van Straaten

unread,
Sep 28, 2006, 7:37:59 PM9/28/06
to
Durchholz wrote:
> (what's the opposite of "closure"?
> "openure"?)

"Open term" is used in mathematical logic. But focusing on the
closed/open distinction isn't very relevant for programming languages
(any more). The usual candidate for the "opposite" of a closure is a
"combinator". The distinction in that case isn't one of closed vs.
open, but rather whether a term depends on (closes over) variables from
its enclosing environment. See e.g. the definition on the Haskell wiki:

http://www.haskell.org/hawiki/Closure

This distinction has more relevance in ordinary modern programming than
the closed vs. open distinction.

> However, other languages have used words that do have everyday
> connotations, at least for newbie programmers. Smalltalk says "block".

Smalltalk makes a syntactic distinction between blocks and other kinds
of functional abstraction. "Block" doesn't translate as well into
languages that don't make that distinction.

> In Haskell, the concept doesn't even have (or need) a name, it's all
> expressions (in various states of evaluation, which doesn't affect the
> semantics because evaluation is lazy anyway); the closest thing with a
> name would be an "unnamed function" (a "lambda" in Lisp terms).

The definition on the Haskell wiki seems to contradict the above a
little, even if the term isn't used as commonly. Besides, the *concept*
still needs a name -- for example, it's used in the Haskell 98 report in
the context of modules, to refer to the requirement that modules not
contain any unbound variables.

This brings up a big reason why focusing on the term used in a
particular programming language is not enough. Concepts like closure
extend beyond the context of a single language feature. You wouldn't
refer to Haskell modules, with their closure requirement, as "blocks" or
"agents" or whatever. "Closure" is actually a term for a property, and
the term happens to be overloaded to also refer to particular kinds of
values which have that property.

Of course, important concepts also tend to extend beyond the context of
a single programming language. If you ever want to communicate across
languages, or understand material that doesn't relate specifically to
the language(s) you know, then knowing the standard terms for the
concepts you depend on is important.

You don't usually get to choose those terms, and they often seem
arbitrary. To me, that just falls in the category of "accepting the
things you cannot change", particularly when the alternatives are
equally arbitrary, culture-dependent, etc.

Anton

Philippa Cowderoy

unread,
Sep 28, 2006, 7:50:23 PM9/28/06
to
On Thu, 28 Sep 2006, Anton van Straaten wrote:

> I was kidding around. (Traditionally, people in parallel universes have some
> characteristic that distinguishes them from their alternate selves.) Sorry if
> you took it personally.
>

Apparently my evil twin's goatee looks rather disturbing.

Jeffrey Mark Siskind

unread,
Sep 28, 2006, 9:10:12 PM9/28/06
to
> I've been thinking as I read this thread about "opening" closures
> and/or "reclosing" them under the bindings of a different environment
> than that in which they were created.
>
> I cannot think of a sane reason why anyone would do this in the
> design of new working code,

See our forthcomming POPL 2007 paper.

M E Leypold

unread,
Sep 28, 2006, 10:43:13 AM9/28/06
to

Joachim Durchholz <j...@durchholz.org> writes:


After following most of that thread, may I introduce another
perspective? I have the impression there are actually 2 things that
are different in Pascal and LISP, that are an issue here:

1. Scoping/Binding (hope that's the right word): In (Emacs) Lisp
procedure the variables are dynamically bound. Actually the
"local" variables are resolved _by name_ at execution time. In
Pascal names are bound lexically (according to the place where
they are defined).

2. Life time of procedure: Pascal procedures are bound to the stack,
any reference to them becomes invalid if the caller returns before
the place of definition (stack wise, I mean). LISP procedures on
the other side, though dynamically bound, are not bound to the
stack with respect to their life time.

AFAIR this thread began with a discussion about wether there needs to
be an extra notion of closures.

The more I think about it, the more my impression is, that in some
sense "closures" are just normal. It's LISP and Pascal that are
lacking something due to compromises in their implementation. So I'd
tend to agree with the poster who suggested just to call closures
procedures (they work just as a beginner would actually expect
procedures to work) and instead accept the necessity to explain the
deficiencies of Pascal procedures (life time locked to the stack) and
LISP functions with dynamically bound variables (variable lookup by
name, this is un-mathematically!, brrr). Those are the things that
would require special notions (say: "stackbound procedures" and "open
functions/expressions").

Regards -- Markus

M E Leypold

unread,
Sep 28, 2006, 8:02:38 PM9/28/06
to

Anton van Straaten <an...@appsolutions.com> writes:

> > In Haskell, the concept doesn't even have (or need) a name, it's all
> > expressions (in various states of evaluation, which doesn't affect
> > the semantics because evaluation is lazy anyway); the closest thing
> > with a name would be an "unnamed function" (a "lambda" in Lisp
> > terms).
>
> The definition on the Haskell wiki seems to contradict the above a
> little, even if the term isn't used as commonly. Besides, the
> *concept* still needs a name -- for example, it's used in the Haskell

I don't think that the concept needs a name. For sake of discussion
I'll take the position that what usually is called closure would be
the normal thing to expect, where as "open terms" or "downward
closures" (procedure whose life time is bound to the call stack) need
explanation and justification. So there! :-)

Regards -- Markus

Anton van Straaten

unread,
Sep 29, 2006, 10:54:50 AM9/29/06
to

If you're talking specifically about a language like Haskell, i.e. a
lazy language with immutable variables, then I think you can get away
with that, up to a point.

But the distinction you're focusing on is one which I addressed earlier

in the message you quoted. I wrote:

> But focusing on the closed/open distinction isn't very relevant for
> programming languages (any more). The usual candidate for the
> "opposite" of a closure is a "combinator". The distinction in that
> case isn't one of closed vs. open, but rather whether a term depends
> on (closes over) variables from its enclosing environment. See e.g.

> the definition on the Haskell wiki:

>
> http://www.haskell.org/hawiki/Closure
>
> This distinction has more relevance in ordinary modern programming
> than the closed vs. open distinction.

In general, without a term like "closure", how would you distinguish
between a function which closes over variables in the surrounding
environment, vs. one which doesn't? That's a fairly interesting
distinction -- for example, the definition of a combinator can be moved
more easily, since it doesn't depend on anything in its immediate
environment; and in languages with mutable variables, a closure's
behavior may change due to mutation of variables in the environment it
was defined in, whereas a combinator has no such dependencies. Aside
from reducing our ability to communicate effectively, saying we don't
need terms for these things is tantamount to saying we don't need to
understand how programs work.

Anton

Benjamin Franksen

unread,
Sep 29, 2006, 5:48:27 PM9/29/06
to
Joachim Durchholz wrote:
> Joachim Durchholz schrieb:
>> Don't give closures a name, say "you can pass around an unevaluated
>> 'expression with holes', just consider that the variables that were
>> defined at the place where the expression is written will be taken from
>> that place, not from the place where the thing will be evaluated".
>
> That is, of course, an overly verbose and still quite inexact (even
> partially wrong) description of what a closure is. It highlights the
> difference between a closure and something that takes some definitions
> from the context where it's evaluated (what's the opposite of "closure"?
> "openure"?)

Hm, carrying over use of the term "closure" in topology I'd say the opposite
(better: the dual) could be named "interior". The interior of a function
would then be its body?

Cheers
Ben

M E Leypold

unread,
Sep 29, 2006, 10:48:53 AM9/29/06
to


Is there a preprint somewhere or an online edition or do I have to
participate ad POPL to see the paper?

Regards - Markus


Joachim Durchholz

unread,
Oct 1, 2006, 6:00:54 AM10/1/06
to
Ray Dillinger schrieb:

> Andreas Rossberg wrote:
>> Joachim Durchholz wrote:
>
>>> Yes, but the code need not be a function, it can be any expression.
>>> In particular one that's inline in the normal flow of the logic.
>
>> Unless you specifically talk about lazy languages, that's simply
>> wrong. Neglecting realisations of toplevel decs ("main"), every
>> closure and every piece of compiled code corresponds to a function
>> that is explicitly written, syntactically as a function expression or
>> definition, in the source program. There is no code representing
>> anything else but explicit function bodies.
>
> I've been thinking as I read this thread about "opening" closures
> and/or "reclosing" them under the bindings of a different environment
> than that in which they were created.
>
> I cannot think of a sane reason why anyone would do this in the
> design of new working code,

There are reasons to do that. There are even seriously considered
proposals for Haskell to introduce parameters that are doing that kind
of stuff.

For example, if you want to have different kinds of error reporting, you
can either add an error_logger parameter to each and any function, or
you can allow the environment to define what error_logger means in some
context.
Essentially, it's simply an implicit parameter, similar to a global
variable. This technique doesn't scale beyond a handful of names or so,
or so, but that doesn't make it entirely unsuitable.

Regards,
Jo

Joachim Durchholz

unread,
Oct 1, 2006, 6:27:32 AM10/1/06
to
Andreas Rossberg schrieb:

> Joachim Durchholz wrote:
>>>
>>> That is also true for SML: Any closure is a pair of code from the
>>> source code and an environment binding free variables.
>>
>> Yes, but the code need not be a function, it can be any expression. In
>> particular one that's inline in the normal flow of the logic.
>
> [...] every closure and

> every piece of compiled code corresponds to a function that is
> explicitly written, syntactically as a function expression or
> definition, in the source program. There is no code representing
> anything else but explicit function bodies.
>
> NB: I remember that I already had the very same discussion with you some
> time ago. I hope you believe me this time. ;-)

I'm not into beliefs ;-)

Actually I still disagree. I simply don't see how this differs from,
say, integer values, which in a sense correspond to integers written in
the program, too (every integer value started with a literal after all).

In other words, either I overlook some important difference between
integer and function values, or the argument doesn't hold up semantically.

Even at the implementation level, you can have code objects that weren't
written that way - even in non-lazy languages. For example, when
constructing a closure, some of the parameters of a function may be
filled with arguments; if function bodies are stored as DAGs, and the
function and arguments are pure, the run-time system could do partial
evaluation and arrive at a DAG that isn't a 1:1 translation of any code.
In fact the set of potential such DAGs in a program is infinite
(countably, I think, though it could even have Aleph-1 cardinality under
lazy evaluation).

If you don't have partial evaluation, your argument could still be
translated to values of sum and product types, amounting to "any sum or
product type is just a variant of a value that's written somewhere in
the source code".

I have a hunch that this kind of argument ignores the structure of
composite values. Whether the primitive parts of a composite values are
integers, constructor names, or functions: for a composite value, the
arrangement in which they were composed does have a massive influence on
its semantics.
Of course, for some argument, abstracting away the structure is entirely
valid, and for others, it is not. I'm not 100% sure what exactly you
mean to argue, so I'm not sure that it's valid in this case.

Regards,
Jo

ross...@ps.uni-sb.de

unread,
Oct 1, 2006, 11:43:01 AM10/1/06
to
Joachim Durchholz wrote:
> Andreas Rossberg schrieb:
> > Joachim Durchholz wrote:
> >>>
> >>> That is also true for SML: Any closure is a pair of code from the
> >>> source code and an environment binding free variables.
> >>
> >> Yes, but the code need not be a function, it can be any expression. In
> >> particular one that's inline in the normal flow of the logic.
> >
> > [...] every closure and
> > every piece of compiled code corresponds to a function that is
> > explicitly written, syntactically as a function expression or
> > definition, in the source program. There is no code representing
> > anything else but explicit function bodies.

> Actually I still disagree. I simply don't see how this differs from,


> say, integer values, which in a sense correspond to integers written in
> the program, too (every integer value started with a literal after all).

For integers, there usually are primitive built-in functions (like +)
that return values that do not occur anywhere in the program. Likewise
for most other primitive types.

There usually are no such primitives for functions. (There might be
primitives that return other primitives, which might then be
represented by closures, but these closures would refer to code that is
essentially just an eta expansion of the primitive (i.e. static, and
unrelated to user code). At least I wouldn't know of any counter
example in typical implementations.)

In particular, something like compose (or any other combinator you are
likely to encounter) is nothing magical. Special-case optimisations
notwithstanding, it's an ordinary function, represented by an ordinary
closure. Applying it constructs another ordinary closure, whose code
represents an inner body of the compose function. I.e.

compose f g x = f (g x)

stands for

compose = \f.\g.\x.f (g x)

Now

h = compose abs sin

will be represented by the straightforward closure

({f|->abs, g|->sin}, \x.f (g x))

Absolutely no magic (of course, I assume non-primitive library code to
be part of "the source program").

> Even at the implementation level, you can have code objects that weren't
> written that way - even in non-lazy languages. For example, when
> constructing a closure, some of the parameters of a function may be
> filled with arguments; if function bodies are stored as DAGs, and the
> function and arguments are pure, the run-time system could do partial
> evaluation and arrive at a DAG that isn't a 1:1 translation of any code.

Runtime specialization is the opposite technique of constructing a
closure, so this does not really relate to your original argument,
which was on closures AFAIR. In any case, I don't think it changes much
about the fundamental observation. The code will still represent a
particular function body, not in its generic form, but in a specialised
copy (i.e. modulo a number of substitutions and reductions).

In the above example, the code in a specialised version,

\x.abs (sin x)

still has a more or less direct correspondence to the lambda in the
source program.

> If you don't have partial evaluation, your argument could still be
> translated to values of sum and product types, amounting to "any sum or
> product type is just a variant of a value that's written somewhere in
> the source code".

Well, almost, except that there are usually primitives delivering
values of sum or product type. Just think of bool.

But then again, I don't see the point you are trying to make by this
comparison.

> I have a hunch that this kind of argument ignores the structure of
> composite values. Whether the primitive parts of a composite values are
> integers, constructor names, or functions: for a composite value, the
> arrangement in which they were composed does have a massive influence on
> its semantics.

I don't understand what you mean by the last sentence, especially since
the whole issue of closures is just an implementation technique anyway,
and hence should not have any effect on semantics.

In any case, my argument would be that functions themselves are
"composite" values (modulo primitives, which are either inlined or eta
expanded in typical implementations to fit this scheme).

Cheers,
- Andreas

Joachim Durchholz

unread,
Oct 1, 2006, 1:09:09 PM10/1/06
to
ross...@ps.uni-sb.de schrieb:

> But then again, I don't see the point you are trying to make by this
> comparison.

Your point (as far as I have understood it) is that "there are no
computed function values, they are all just trivial compositions of
functions that you can see in the source".

My point in response to this is twofold:

At the *semantic* level, I think this point can be applied to all
values. Any value is some combination of unchanged primitives and
composition operators.
An example of this argument is integer arithmetic. You'd say that 4 is
created out of 3 by a program that increments it input by one; however,
semantically, the program is incrementing Succ Succ Succ Zero to
Succ Succ Succ Succ Zero, and both Succ and Zero are already in the
code. No magic and no creation of new values involved.
So functional values are no different from integers (or anything else
constructed from a finite number of primitive building blocks). Which
means that your argument, while technically true, doesn't describe
anything that distinguishes functions from other kinds of values.

At the *implementation* level, there can be differences.
There are programming language implementations that translate to formats
that can't easily be changed after the fact. Compilers that translate to
machine code are in that class by default (unless the CPU has a very
unusual instruction architecture, or the machine code comes with a lot
of tagging). Most bytecode architectures are in that class, too.
In such an environment, your view is correct. If a functional value is
passed around, the code that actually gets executed is never changed, it
is just combined in various interesting ways.
Then there are environments that translate to some variations of ASTs
(actually it's DAGs most of the time, since names are usually replaced
with links to the values that they represent). Haskell interpreters tend
to do this; actually one widely-used way of executing Haskell seems to
be a sequence of DAG transformation steps. Please note that this isn't
necessarily tied to lazy evaluation, it is (as far as I can see right
now) tied to partial evaluation, i.e. replacing a node in a DAG with a
shorter representation (i.e. replace code that evaluated to Zero with a
node contains a link to the memory cell that represents Zero, or similar
transformations).
In such an environment, you are not correct. Most functions will
transform into something that isn't directly recognizable from the
source code anymore, particularly after a few rounds of expanding and
partially evaluating recursive functions. Actually I think that
undecidability issues would make any mapping other than simulating the
evaluation process would be undecidable.

In other words, what I have understood of your point doesn't make sense
at the semantic level, and is just partially valid at the implementation
level.

Regards,
Jo

M E Leypold

unread,
Oct 1, 2006, 6:21:16 AM10/1/06
to

Joachim Durchholz <j...@durchholz.org> writes:

> > I've been thinking as I read this thread about "opening" closures
> > and/or "reclosing" them under the bindings of a different environment
> > than that in which they were created.
> > I cannot think of a sane reason why anyone would do this in the
> > design of new working code,
>
> There are reasons to do that. There are even seriously considered
> proposals for Haskell to introduce parameters that are doing that kind
> of stuff.

Oh no, please not.

> For example, if you want to have different kinds of error reporting,
> you can either add an error_logger parameter to each and any function,
> or you can allow the environment to define what error_logger means in
> some context.

I see. That seems to make some practical sense. Nonetheless I doubt
wether the resulting "corruption" of the language design would be
worth the benefits.

> Essentially, it's simply an implicit parameter, similar to a global
> variable. This technique doesn't scale beyond a handful of names or
> so, or so, but that doesn't make it entirely unsuitable.


Regards -- Markus

Joachim Durchholz

unread,
Oct 3, 2006, 7:31:54 AM10/3/06
to
Tomasz Zielonka schrieb:
> Joachim Durchholz wrote:
>> I have seen knowledgeable people say that monads are about sequencing
>> actions, and state that even for the List monad.
>
> I wouldn't say they are wrong - it's just that in the List monad a
> single sequence of actions may have an arbitrary number of results.
> That's why sometimes it is also called non-determinism monad.

Everything that involves nested function calls can be seen as sequencing
actions. In that sense, yes, monads are about sequencing - but that's
just one property among many, possibly not the one that one is most
interested in at a given time, and certainly not the one that will allow
newbies to grok monads fastest.

Regards,
Jo

Philippa Cowderoy

unread,
Oct 3, 2006, 8:40:43 AM10/3/06
to
On Tue, 3 Oct 2006, Joachim Durchholz wrote:

> Everything that involves nested function calls can be seen as sequencing
> actions. In that sense, yes, monads are about sequencing - but that's just one
> property among many, possibly not the one that one is most interested in at a
> given time, and certainly not the one that will allow newbies to grok monads
> fastest.
>

There's more to it than that - >>= explicitly provides a hook for
sequencing, and every monad gets to supply its own notion of sequencing on
top of that. It's one of the most important properties, on a par with
those provided by return and the type-level consequences and IMO more
important than the ability to usefully perform higher-order computations
as indicated by join. Without that sequencing, do notation wouldn't work -
nor would monadic IO, all the assorted state monads, parsing monads,
exception monads...

--
fli...@flippac.org

Ivanova is always right.
I will listen to Ivanova.
I will not ignore Ivanova's recomendations.
Ivanova is God.
And, if this ever happens again, Ivanova will personally rip your lungs out!

Joachim Durchholz

unread,
Oct 3, 2006, 3:56:15 PM10/3/06
to
Philippa Cowderoy schrieb:

> On Tue, 3 Oct 2006, Joachim Durchholz wrote:
>
> Without that sequencing, do notation wouldn't work -
> nor would monadic IO, all the assorted state monads, parsing monads,
> exception monads...

I wouldn't associate parsing and exception with sequencing.

Regards,
Jo

Tomasz Zielonka

unread,
Oct 3, 2006, 5:07:50 PM10/3/06
to

Think about this:

In parsing monads sequencing corresponds to concatenation (usually
denoted by white-space or comma) in EBNF.

In the exception monad you specify how to sequence computations in the
presence of exceptions, for example:

Error e >>= f = Error e
...

This tells that the "f" computation should be abandonded if the
preceding computation raised an error

Best regards
Tomasz

Philippa Cowderoy

unread,
Oct 3, 2006, 5:55:27 PM10/3/06
to
On Tue, 3 Oct 2006, Joachim Durchholz wrote:

> Philippa Cowderoy schrieb:
> > On Tue, 3 Oct 2006, Joachim Durchholz wrote:
> >
> > Without that sequencing, do notation wouldn't work - nor would monadic IO,
> > all the assorted state monads, parsing monads, exception monads...
>
> I wouldn't associate parsing and exception with sequencing.
>

Sequencing is one of the most fundamental operations in every metalanguage
I've seen used to define grammars. It's also of particular importance when
analysing behaviour and optimising parsers. As for exceptions, what's
happening is that the control flow is being 'reified' so that the monad
implementation can make jumps in it - that control flow is a sequencing of
dependencies. If you don't buy that, look at how the Maybe monad and its
relatives are used to gain something equivalent.

--
fli...@flippac.org

Society does not owe people jobs.
Society owes it to itself to find people jobs.

Neelakantan Krishnaswami

unread,
Oct 4, 2006, 12:44:49 PM10/4/06
to
In article <efueu4$b6l$1...@online.de>, Joachim Durchholz wrote:
>
> I wouldn't associate parsing and exception with sequencing.

If I write:

foo(raise E1, raise E2)

does this expression raise the exception E1, or the exception E2?

Having an answer means specifying the order of evaluation, which
means specifying a particular sequencing.

--
Neel R. Krishnaswami
ne...@cs.cmu.edu

0 new messages