Version 18 of Functional composition

Updated 2004-04-27 15:36:00

Richard Suchenwirth - More steps towards functional programming... When reading about, and playing Haskell, I met the concept of functional composition again, where you conglomerate some functions into one, so in pseudocode the application of the functional object (f . g) to a variable x

 (f . g)(x)

is equivalent to

 f(g(x))

This, of course, can again be had in Tcl - we just have to compromise that the infix operator "." as used in Haskell must be moved to prefix position (before the arguments), as Polish notation requires - but this allows us to pass any number of arguments, not just two. Also, considering that this code should be runnable in a wish, "." is a (maybe the only) taboo name for a proc: defining "proc ." destroys the primary toplevel window, often causing wish to exit. So I changed the name to the slightly bigger, but harmless comma: ",".

The code below will create a new procedure, which needs a name. I have first found out in Lambda in Tcl that [info level 0] makes a nice self-referential name: it tells how the "," proc was called. As opposed to just counting up a lambda index, this has the added advantage that it avoids memory leaks - execute the same code as often as you wish, the name is always the same and thus overwrites the previous instance...

For now I assume that the generated procedure takes a single argument (call it "x") - but that could be a list. However, the functions to be nested are not restricted to a single word. Rather, if you brace (or quote) them, they may have more leading arguments (in technical terms, currying- see Custom curry), as demonstrated by the "string toupper" example below. In Tcl's glorious spirit of "everything is a string" (so don't be afraid of nothing ;-), we just build up a well-formed proc body (the closing braces were factored out to prevent over-long lines), declare that with the fancy name and the boring "x" argument, return the name, and off we go...

 proc , args {
    set   name    [info level 0]
    set   closing [string repeat {]} [expr [llength $args]-1]]
    set   body   "[join $args { [}] \$x $closing"
    proc $name x $body
    set   name
 }

if 0 {Now testing... both use cases of "on-the-fly", and saving the generated name in a variable for subsequent use: the first example is strictly alphabetic, while in the second, "T" comes before "c" and" "l" - where it belongs ;-}

 % [, lsort {string toupper}] {z R a}
 A R Z
 % set try [, {string tolower} lsort]
 , {string tolower} lsort
 % info body $try
 string tolower [lsort $x ]
 % $try {l c T}
 t c l

if 0 { Final note: Reading on Haskell, I sometimes have a vague feeling of inferiority: They have so much (at a cost of increased syntax complexity, types and all) - but then again, our simple Tcl can catch up in 7 lines of code...


Reinhard Max contributed this condensed version:

 proc ��· {args} { 
  proc [set name [info level 0]] x "[join $args { [}] \$x [string repeat \] [expr {[llength $args]-1}]]"
  set name 
 } 

(RS)...or this one-liner:-)

 proc , args {append _ [proc [set _ [info level 0]] x "[join $args { [}] \$x [string repeat \] [expr {[llength $args]-1}]]"]}

CL: There are deep things to say about functional composition. Meta-summary: functions are a sufficient model for *anything* interesting/significant, and composition is the natural operation on functions, so functional composition is a universally-expressive idiom. 'Nother way to say the same: we do SOOOOOOO much with the duality between code and data. Well, look at functional composition: it's the natural first step in viewing code (operation, function) as data (subject of algebraic analysis).


See Playing Joy for a Forth-like language that does everything with functional composition.


DKF remarked in the chat: "Actually, the most well known combinator of all is 'o' (usually written inline) which does function composition: o(f,g)(x) == f(g(x))" - RS likes "o" better than the comma.


Good usage examples (with the fancy "o" name) are at Functional imaging.


Category Concept | Arts and crafts of Tcl-Tk programming | Category Functional Programming