** Summary ** '''apply''' — apply an value as a command ** Documentation ** [http://www.tcl.tk/man/tcl/TclCmd/apply.htm%|%official reference]: ** Synopsis ** '''apply''' ''func'' ?''arg1 arg2'' …? ** Description ** [Tcl] core command, 8.5 and newer '''apply''' applies the function ''func'' to the arguments ''arg1 arg2 …'' and returns the result. The function ''func'' is a two element list {''args body''} or a three element list {''args body namespace''} (as if the [list] command had been used). The first element ''args'' specifies the formal arguments to ''func''. The specification of the formal arguments ''args'' is shared with the [proc] command, and is described in detail in the corresponding manual page. The ''body'' is a script that will be evaluated with local variables, just as in a procedure. The optional ''namespace'' specifies what the current namespace will be when the ''body'' is evaluated (by comparison, a procedure's current namespace is the namespace that its command is in); if omitted, the global namespace (`::`) will be current. ** See Also ** [proc]: [uplevel]: [If we had no proc]: ** Examples ** [Vogel spiral]: uses [[apply] as the script for [[`[bind]`] ====== proc map {lambda list} { set result {} foreach item $list { lappend result [apply $lambda $item] } return $result } map {x {return [string length $x]:$x}} {a bb ccc dddd} → 1:a 2:bb 3:ccc 4:dddd map {x {expr {$x**2 + 3*$x - 2}}} {-4 -3 -2 -1 0 1 2 3 4} → 2 -2 -4 -4 -2 2 8 16 26 ====== ** Implementations for 8.4 and before ** see [TIP] [http://www.tcl.tk/cgi-bin/tct/tip/194%|%194], which also gives an illustrative implementation in pure-Tcl. ====== proc apply {fun args} { set len [llength $fun] if {($len < 2) || ($len > 3)} { error "can't interpret \"$fun\" as anonymous function" } lassign $fun argList body ns set name ::$ns::[getGloballyUniqueName] set body0 { rename [lindex [info level 0] 0] {} } proc $name $argList ${body0}$body set code [catch {uplevel 1 $name $args} res opt] return -options $opt $res } ====== [RS] wonders, however, how the following simpler take is insufficient: ====== proc apply {fun args} { foreach {argl body ns} $fun break namespace eval $ns [list foreach $argl $args break] namespace eval $ns $body } ====== Testing: ======none % apply {x {expr $x*$x}} 5 25 % apply {{x y} {expr hypot($x,$y)} foo} 3 4 5.0 ====== [NEM]: The difference is that in your version parameters are persistent namespace variables, rather than local to the procedure. Consider: ======none % interp alias {} test1 {} apply {x { expr {$x * $x} }} test1 % interp alias {} test2 {} apply {x { set y [test1 12]; return $x }} test2 % test2 "Hello!" 12 ====== Which isn't what you want, I expect. - [RS]: Indeed. In fact, I didn't want namespaces at all :) - just because the other version had them... I started with this: ====== proc apply {fun args} { foreach {argl body} $fun break foreach $argl $args break eval $body } ====== ---- [Bryan Oakley]: I don't like the syntax. Why is the function itself a list? What is wrong with a syntax that lets me use it like this: ====== button .b -command [apply arglist body arg1 arg2 ...] ====== ... if you need a namespace it could be: ====== button .b -command [apply arglist body -namespace foo arg1 arg2] ====== ... and if you want "-namespace" to not be treated as part of the apply command but rather one of the extra arguments you could do: ====== button .b -command [apply arglist body -- -namespace foo arg1 arg2] ====== [MS] replied in [https://groups.google.com/d/msg/comp.lang.tcl/puxORvH0H4A/6wqtwY4Kf54J%|%Re: 8.5 "apply" command (was Re: TK: question about "-command" usage with "{}" and double quoter)] Miguel Sofer ,2006-03-29, that structure is required in order to be able to cache a bytecompiled body and avoid recompilation at each step. The anonymous function carries all the info necessary for compilation {argList body namespace} in a single Tcl_Obj. Note also that this makes it easier to have ====== set anon [list argList body] button .b -command [list apply $anon arg1 arg2] button .b1 -command [list apply $anon arg3 arg4] ====== and have both buttons share the anonymous function - including the bytecompiled structures. [NEM]: It's also pretty easy to create a constructor function (which apply is not): ====== proc func {params body args} { set ns [uplevel 1 { namespace current }] linsert $args 0 ::apply [list $params $body $ns] } button .b -command [func arglist body arg1 arg2 ...] # etc... ====== I personally use a constructor proc that snapshots the lexical closure into a dict: ====== proc func args { set ns [uplevel 1 { namespace current }] set env [uplevel 1 { capture }] set params [linsert [lrange $args 0 end-1] 0 __env__] set body [list dict with __env__ [lindex $args end]] return [list ::apply [list $params $body $ns] $env] } proc capture {} { set env [dict create] foreach name [uplevel 1 { info locals }] { upvar 1 $name var catch { dict set env $name $var } ;# no arrays } return $env } ====== Which I can then use like: ====== proc person {name age} { func key { set $key } } proc ask {object args} { uplevel 1 $object $args } set neil [person "Neil Madden" 25] puts "Neil's age is [ask $neil age]" ====== I've also on occasion used a further variation that wraps the body in a call to [expr]. I'll leave "-namespace" as an exercise for the reader. ---- Also, in the days before Tcl 8.5: What: apply Where: http://www.glinx.com/%7Ehclsmith/plugin.html ??? Description: Version of the apply procedure as discussed on news:comp.lang.tcl during February, 1997. Versions of Tcl C and scripting routines as well as a lisp-backquote-like proc are available. Now supports Tcl 8.x. Updated: 09/1999 Contact: mailto:hclsmith.delete@glinx.delete.com (Hume Smith) [NEM] wonders if the c.l.t discussion mentioned is this one: [http://groups.google.com/forum/#!msg/comp.lang.tcl/lPFTs5Nk16c/vFsk1Air_uoJ%|%Feature request: 'apply' command] ,comp.lang.tcl ,1997-01-26. If so, then the ''apply'' mentioned there seems more related to [{*}] than to our current ''apply'' command. Or perhaps a version of this: ====== proc old-apply {cmd args} { uplevel 1 $cmd $args } ====== ---- [WHD]: The Tcl 8.5 man page has this example: ====== proc map {lambda list} { set result {} foreach item $list { lappend result [apply $lambda $item] } return $result } # Returns {1:a 2:bb 3:cc 4:dddd} map {x {return [string length $x]:$x}} {a bb ccc dddd} ====== This strikes me as really bad style: it means that [map] can only be used with "lambdas"; you can't use normal commands unless you cast them as lambdas. So what would be better? It is already common style to pass command prefixes as callbacks. "The cmd argument is a [command prefix] to which two additional arguments will be added..." Suppose we wrote `map` like this instead: ====== proc map {prefix list} { set result {} foreach item $list { lappend result [{*}$prefix $item] } return $result } ====== Then we can write ====== # Returns {1:a 2:bb 3:cc 4:dddd} map {apply {x {return [string length $x]:$x}}} {a bb ccc dddd} ====== But we can also write ====== # Returns {1 2 3 4} map {string length} {a bb cc dddd} ====== An [[apply] expression then becomes just another kind of command prefix. [NEM] This is indeed good style, as is always using a constructor function rather than a literal: ====== proc lambda {params body args} { set ns [uplevel 1 { namespace current }] list ::apply [list $params $body $ns] {*}$args } map [lambda x { ... }] $xs ====== [Lars H]: The virtue of "constructor function rather than literal" is highly debatable, IMO. Capturing the namespace context is good, but since that constructor function recreates the lambda [Tcl_Obj] every time it is called, the above has the severe drawback that the same lambda is going to get recompiled over and over again. A literal lambda persists, so it is only compiled once. [NEM]: What's that phrase about premature optimisation? Byte-code compilation is fast and if you are constructing a lambda inside a tight loop then simply move it out. Not properly encapsulating code because of some weird obsession with eliminating a few microseconds is just wrong. [Lars H]: Is this a fear of complex literal data I see? Or just a reaction on having one's ''style'' put under scrutiny? Claims that one style is "always" good ''deserve'' to be critized. The "simply move it out" approach hurts other goals for good code, such as keeping related things together, so why should one always take precendence over the other? As for the "premature optimisation": It's not so much the ''time'' for recompilation that concerns me (even though this is obviously low-hanging fruit), but rather that the object is being created again and again — the ''use'' of a constructor function to produce a constant. For one, it is tantamount to [shimmering], which IMHO is best avoided from the start rather than eliminated in a clean-up phase. Second, it can at times (although probably not in this case) be a severe memory bloat to recreate a [Tcl_Obj] rather than sharing one that already exists. Sure, the constructor function can use [memoizing] to counter that, but this introduces the problem of life-cycle management, and complicates the code. The literal constant is just so much easier! The general argument ''for'' constructor functions — that less code need to be modified if the underlying representation changes — is hardly relevant for [apply] lambdas, so advocating their use here can itself be considered an act of premature optimisation. ;-) [MS] thinks that this is a whole different kettle of fish. Depending on the app, and how much memory management may be needed or acceptable, the optimal may be literals (live "forever", shared), simple constructor (garbage collected, not shared), memoizing constructors (live until explicitly freed, shared), some kind of fancy memoizing constructors (could eg free lambdas that were not used in the last X seconds, shared), ... [WHD]: If we had true compile-time macros, a la [Lisp] or [Scheme], could we possibly have it both ways? If `lambda`, as described above, were a macro, you'd only pay the compilation penalty once. [NEM]: You don't really need macros. A sufficiently smart byte-compiler could inline the lambda constructor into the body it appears in. I doubt very much whether the performance gain is at all worth it, though -- we're talking about a constant-time operation (assuming the body of the lambda is not changing on each iteration, in which case a literal would be no help) that generally takes <10us by my measurements. As Miguel points out, what is right for your app might be a trade-off. As Lars even acknowledges, a constructor function is free to memoize, effectively transforming itself into the literal version. Literals also live forever, so they have no particular advantage over memoizing. "Encapsulation is good" is one of the few really solid ideas from software engineering. Even for lambdas this encapsulation is a good idea: e.g. you can add enter/exit tracing to all lambdas easily, or bundle some extra state, or perhaps wrap the lambda in a coroutine or thread so that long-running computations can be transparently handed off without blocking execution. Other advantages are that you avoid many cases of [Tcl Quoting%|%overquoting] by having implicit list-quoting, avoid ever generating a string rep, can wrap the body in an [expr] or [dict with] to get custom behaviours, etc, etc, etc. Literals bad functions good! ---- [RS] 2008-10-15: Has it been discussed that [[apply] might also accept command names, i.e. non-lambdas? Such that ====== apply $f $x $y ====== would then work with ====== set f {{a b} {expr {sqrt($a*$a+$b*$b)}}} ====== as well as ====== set f tcl::mathfunc::hypot ====== ? - In fact, it's already in recent Tcl sources - [dgp] pointed me to tclProc.c, search for JOE_EXTENSION. <> ---- <> Avoid local variable creation [HaO] 2012-07-18: `apply` may also be used to get just a frame for local variables. *** Example *** A module is placed in the namespace `ns` and requires one-time init code. The local variables of the init code should not be set as namespace global. ****Solution with global commands**** ====== namespace eval ::ns { # Module variable to initialize from some calculations variable moduleVar 1 # Module initialisation # variable should be local but is global due to global scope set counter 500 # do some calculation to find initial value incr counter $counter # and initialize module variable with result set moduleVar $counter # unset local variable unset counter } ====== Set local variables must be manually unset. ****Solution with one-time init proc**** ====== namespace eval ::ns { variable moduleVar 1 } # Module initialisation proc ns::init {} { variable moduleVar # locale variable set counter 500 incr counter $counter set moduleVar $counter } ns::init rename ns::init "" ====== The init-proc must be manually called and deleted **** Solution with apply **** ====== namespace eval ::ns { variable moduleVar 1 } # Module initialisation apply {{} { variable moduleVar set counter 500 incr counter $counter set moduleVar $counter } ns} ====== Similar to the upper init-proc method but no delete necessary. <> Command | Package