Version 7 of Accumulator Generators

Updated 2002-06-19 13:37:24

Paul Graham invited solutions to his Accumulator Generator [L1 ] problem written in various programming languages.

Here is the problem:

Write a function foo that takes a number n and returns a function that takes a number i, and returns n incremented by i. Note: (a) that's number, not integer, (b) that's incremented by, not plus.

After a slew of languages are presented that solve the problem, he concludes with:

Some languages are not represented here, either because you can't write this program in them (short of Greenspun's Tenth Rule) or because no one has yet sent me the code for that language. If you know how to write this program in a language that isn't listed here, please send it along. (Please make sure, first, that it actually does the same thing as these solutions.)

(Greenspun's Tenth Rule: any sufficiently complicated C or Fortran program contains an ad hoc informally-specified bug-ridden slow implementation of half of Common Lisp.)

Now, since Tcl is meant to be extended (like Lisp, you extend the langauge to solve problems), I don't think that Greenspun's rule applies. Now, that being said, Tcl doesn't support closures natively, but you can add that capability (sans any GC) to the language quite naturally (see Closures). To keep things short, I offered a solution that didn't use any generalized closure proc, but solved the problem directly:

 namespace eval foo {variable instance 1}
 proc foo {n} {
    set id [namespace eval foo {incr instance}]
    namespace eval foo::${id} [list variable n $n]
    proc foo::${id}::foo {i} { 
        variable n
        set n [expr {$n+$i}]
    }
    return foo::${id}::foo
 }

I haven't heard from him since... (and he did accept my lua submission). I am sure the above code snippet is not the optimal solution. Anyone care to improve upon it (or offer a better solution), post it here and then submit it to Graham?

-- Todd Coram


RS prefers pseudo-closure with default arguments as it appears less heavyweight (no namespace, no garbage collection needed..) The following variation from procs as objects is as long as the above code, but somehow has a "musical", rhythmic quality:

 proc foo n {
   set name [clock clicks] ;# get a (hopefully) unique name
    proc $name "i {n $n}" {
        set self [lindex [info level 0] 0]
        set n [expr {$n+$i}]
        proc $self "i {n $n}"  [info body $self]
        set n
   }
   set name
 }

Arjen Markus I will not supply a solution using aliases (yet a third way to achieve the effect), but rather I would like to comment on the term function: it seems to me that these functions with side-effects are not functions in the proper sense of the word. They are more akin to subroutines in Fortran (and they have the same bad habits as C's not-so-functional functions). Proper functions should return a value and that value should be the same whenever the arguments are the same.

I mean this comment as more than just a word game!


Depends on whether you view closures as side-effects. The accumulator variable n is really local to the function (it is enclosed---or captured---by it), so while the function is not functionally pure, it has no global side-effects (n is private to the generated function). -- Todd Coram


I don't understand the "increment, not plus" requirement. Is he asking that, for example, 2.5 + 3 be calculated as (10 * 2.5 + 10 * 3) / 10? I don't get it.