Richard Suchenwirth 2005-04-02 - Say you want to make a multiplication table for an elementary school kid near you. Easily done in a few lines of Tcl code:

proc multable {rows cols} { set res "" for {set i 1} {$i <= $rows} {incr i} { for {set j 1} {$j <= $cols} {incr j} { append res [format %4d [expr {$i*$j}]] } append res \n } set res }

The code does not directly puts its results, but returns them as a string - you might want to do other things with it, e.g. save it to a file for printing. Testing:

% multable 3 10 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30

Or print the result directly from wish:

catch {console show} puts "[multable 3 10]"

Here's a different way to do it à la functional programming:

proc multable2 {rows cols} { formatMatrix %4d [outProd * [iota 1 $rows] [iota 1 $cols]] }

The body is nice and short, but consists of all unfamiliar commands. They are however better reusable than the *multable* proc above. The first formats a matrix (a list of lists to Tcl) with newlines and aligned columns for better display:

proc formatMatrix {fm matrix} { join [lmap row $matrix {join [lmap i $row {format $fm $i}] ""}] \n }

hort again, and slightly cryptic, as is the "outer product" routine, which takes a function f and two vectors, and produces a matrix where f was applied to every pair of a x b - in APL they had special compound operators for this job, in this case "°.x":

proc outProd {f a b} { lmap i $a {lmap j $b {$f $i $j}} }

Again, lmap (the collecting foreach) figures prominently, so here it is in all its simplicity:

proc lmap {_var list body} { upvar 1 $_var var set res {} foreach var $list {lappend res [uplevel 1 $body]} set res } #-- We need multiplication from [expr] exposed as a function: proc * {a b} {expr {$a * $b}} #-- And finally, ''iota'' is an [integer range generator]: proc iota {from to} { set res {} while {$from <= $to} {lappend res $from; incr from} set res }

With these parts in place, we can see that *multable2* works as we want:

% multable2 3 10 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30

So why write six procedures, where one did the job already? A matter of style and taste, in a way - *multable* is 10 LOC and depends on nothing but Tcl, which is good; *multable2* describes quite concisely what it does, and builds on a few other procs that are highly reusable. Should you need a unit matrix (where the main diagonal is 1, and the rest is 0), just call *outProd* with a different function (equality, ==):

% outProd == [iota 1 5] [iota 1 5] {1 0 0 0 0} {0 1 0 0 0} {0 0 1 0 0} {0 0 0 1 0} {0 0 0 0 1}

which just requires expr's equality to be exposed too:

proc == {a b} {expr {$a == $b}}

One of the fascinations of functional programming is that one can do the job in a simple and clear way (typically a one-liner), while using a collection of reusable building-blocks like lmap and *iota*. And *formatMatrix* and *outProd* are so general that one might include them in some library, while the task of producing a multiplication table may not come up any more for a long time...

SS agrees 100% with the spirit of this page, that's why Jim has lmap and range (that is similar to the *iota* of this page).