proc func {name argl body} {proc $name $argl [list expr $body]}(Might have called it fun as well... it sure is.) That's all. A collateral advantage is that all expressions are braced, without me having to care. But to not make the page look so empty, here's some examples for func uses:
func fac n {$n<2? 1: $n*[fac [incr n -1]]} func gcd {u v} {$u? [gcd [expr $v%$u] $u]: $v} func min {a b} {$a<$b? $a: $b} func sgn x {($x>0)-($x<0)} ;# courtesy rmaxPity we have to make expr explicit again, in nested calls like in gcd... But func isn't limited to math functions (which, especially when recursive, come out nice), but for expr uses in testing predicates as well:
func atomar list {[lindex $list 0] eq $list} func empty list {[llength $list] == 0} func in {list element} {[lsearch -exact $list $element] >= 0} func limit {x min max} {$x<$min? $min: $x>$max? $max: $x} func ladd {list e} {[in $list $e]? $list: [lappend list $e]}Exposing expr operators as Tcl commands goes quite easy too:
foreach op {+ * / %} {func $op {a b} "\$a $op \$b"}For "-", we distinguish unary and binary form:
func - {a {b ""}} {$b eq ""? -$a: $a-$b}Having the modulo operator exposed, gcd now looks nicer (from Playing with rationals):
func gcd {u v} {$u? [gcd [% $v $u] $u]: abs($v)}For unary not I prefer that name to "!", as it might also stand for factorial - and see the shortest function body I ever wrote :^) :
func not x {!$x}It could have been shortened by one byte, though :^)
func not x !\$xFeel free to add more meaningful examples! In any case, no one can blame me for not using return in these sweet one-liners... :)Without big mention, functions implemented by recursion have a pattern for which func is well suited (see fac and gcd above). Another example is this integer range generator (starts from 1, and is inclusive, so [iota1 5] == {1 2 3 4 5}):
func iota1 n {$n == 1? 1: [concat [iota1 [- $n 1]] $n]}
AM (1 june 2004) I have been musing over another, related subject:
- Define functional relations between variables (possibly defining an equation)
- Use high-level commands to actually solve the equation
RS 2006-01-25: If you have many parameters as global variables, you can extend func to import all of them. This runs the risk of side-effects, but here you go:
proc func {name argl body} { proc $name $argl "eval global \[info globals\]; expr {$body}" }Testing:
% set a 6 6 % func f x {$x * $a} % f 7 42
Arts and crafts of Tcl-Tk programming