[Richard Suchenwirth] 2005-04-02 - [lmap] is a "collecting [foreach]" which returns a list of its results. In [Jim] it is built in, but it can be easily had in pure Tcl: proc lmap {_var list body} { upvar 1 $_var var set res {} foreach var $list {lappend res [uplevel 1 $body]} set res } Several usage examples are at [Multiplication tables]. [Lmap] is a compromise between Tcl and the classical [functional programming] function [map], in that it takes a "quasi-[lambda]" which is split up into the ''_var'' name and the ''body'' arguments. However, this style is well-known from [foreach], and somehow reads better: lmap i {1 2 3 4 5} {expr $i*$i} vs. map [lambda i {expr $i*$i}] {1 2 3 4 5} ---- [Jim]'s [lmap] uses [continue] to skip the accumulation of the current iteration, so it works like [map] and [filter] at the same time. In Jim lmap supports multiple lists in input like the real [foreach], so you can do interesting things like this: . lmap a {1 2 3} b {A B C} {list $a $b} {1 A} {2 B} {3 C} Multiple lists + accumulation + continue to skip makes it also somewhat similar to list comprehension (but simpler to use in the my (SS) opinion). ---- A cute variation is ''fmap'' (influenced by ApplyAll in Backus' FP; [Joy] has a comparable operator in ''cleave'') which maps a list of functions on one argument: proc fmap {functions x} {lmap f $functions {$f $x}} Then we can write a file reader like this: proc << filename {lindex [fmap {read close} [open $filename]] 0} [NEM] I like that one! There is an mmap function that I wrote with [Monadic TOOT] which is similar to lmap (look about 1/3 way down that page). Instead of using continue, it uses a maybe monad to decide which results to accumulate. (Actually, it's quite general, and any monad could be used). ---- [iu2] 2009-10-15, I like to eliminate the "helper variables": proc lmap {list body} { upvar 1 0 var ;# $0 will be available automatically! set res {} foreach var $list {lappend res [uplevel 1 $body]} set res } So we can write lmap {1 2 3 4 5} {expr $0 * $0} As I often replace the original list variable with the mapped list, instead of set list [lmap $list {expr $0 * $0}] I can do lmap! list {expr $0 * $0} where lmap! is proc lmap! {listvar body} { upvar 1 $listvar res set res [lmap $res $body] } Finally, the current tcl constructs are just fine for a one liner set list2 {}; foreach x $list {lappend list2 [expr {$x * $x}]} ---- [DKF]: Note that lmap imposes quite a cost: ====== % time {lmap i {1 2 3 4 5} {expr {$i*$i}}} 100000 24.6734621 microseconds per iteration % time {set res {}; foreach i {1 2 3 4 5} {lappend res [expr {$i*$i}]};set res} 100000 7.2637871 microseconds per iteration % time {apply {l {set res {}; foreach i $l {lappend res [expr {$i*$i}]};set res}} {1 2 3 4 5}} 100000 2.75048408 microseconds per iteration ====== So... lmap is 9 times slower than inlining it (the use of [apply] shows that the effect of compilation of [foreach] is a fair part of it, but that cuts both ways). <> Category Functional Programming