[FM] : Here is a proc whose only goal is to "inline" one lmap loops, when its boundaries are known at compile time. <<br>>
In short, it's about the kind of `lmap` we write just for convenience, to shorten the code, because we are lazy to write long command. For instance :
======
proc essai.1 {L} {
lmap i {1 2 3} {
lindex $L $i
}
}
======
The optproc below just creates a proc that is removing the loop totally to produce a body like :
======
list [lindex $L 1] [lindex $L 2] [lindex $L 3]
======
Very simple proof of concept :
======
proc optproc {name args body} {
rename lmap _lmap
proc lmap args {
set body [lpop args]
set script {}
foreach {vars listval} $args {
if {! string match {$*} $listval} {
# not a variable : $listval"
if {! string match {\[*\]} $listval} {
# "not a command "
# "litteral loop :"
set script {list }
set len [llength $listval]
foreach val $listval {
foreach var $vars {
set string [string map [list \$$var $val] $body]
}
append script \ \[$string\]
}
}
}
}
return $script
}
set script [eval $body]
uplevel [list proc $name $args $script]
rename lmap {}
rename _lmap lmap
}
======
And we can use it as :
======
optproc essai.2 {L} {
lmap i {1 2 3} {
lindex $L $i
}
}
======
Then we can measure the difference :
======
set L {1 2 3 4 5 6}
timerate {essai.1 $L}
# 4.991574 µs/# 200337 # 200337 #/sec 999.997 net-ms
timerate {essai.2 $L}
0.445589 µs/# 2244217 # 2244219 #/sec 999.999 net-ms
======
This kind of « convenience lmap » is more than one order of magnitude slower !
Is there any possibility to optimise the lmap code when the loop is known at compile time ?
[APN] The [Sugar] package which is a general macro implementation may interest you.
[FM] [Sugar] looks very interesting and may be one good workaround solution. But the links are dead on the wiki page, so can't check it... Personnally, I prefer this to be natively supported. Very often, i've written things like :
======
foreach e {very long list of elements} {
Typedlist create $e
}
======
I think Tcl API has everything needed to detect such a situation (ex: func Tcl_WordknowAtCompileTime). If the list values are all known at compile time, rather than creating a loop in bytecode, which will be slower, it should be possible to loop in the C code during the compilation to create the bytecode accordingly. The difficulty is to subst in the body only on the loop variables.
... Some times later...
Or, if ever, maybe a new ensemble command ?
======
inline lmap e {const list} {
....
}
======
So there would be a man page explaining this.