Firstly, brace your expressions. Really. It means that Tcl can generate bytecode for the expression instead of needing to prepare everything every time.
proc __val x {set x}
proc mul {x y } {
return [expr {$x*$y}]
}
proc factorial {x } { return if [expr {$x==0}] {__val 1} {__val [mul $x [factorial [expr {$x-1}]]]} }
set x 4
mul $x [factorial [expr {$x-1}]]
With that, we get the slightly less confusing error can't use empty string as operand of "*"
and the trace will tell you that this is coming from the (expression inside the) top level call to mul
. Which means that the result of factorial
is the empty string. What else could be going wrong there?
Well, there is abuse of return
. Yes, return
accepts many arguments that are formed into the result dictionary (that's where error traces are stored, for example) but what you are doing is highly unlikely. Let's fix that almost syntactic error (and add some newlines for clarity).
proc __val x {set x}
proc mul {x y } {
return [expr {$x*$y}]
}
proc factorial {x } {
return [if {$x==0} {__val 1} {
__val [mul $x [factorial [expr {$x-1}]]]
}]
}
set x 4
mul $x [factorial [expr {$x-1}]]
Behold, it now works. But we can shorten it.
# Magic namespace contains function definitions
proc tcl::mathfunc::factorial x {expr {
$x == 0 : 1 ? $x * factorial($x - 1)
}}
# I ought to brace this... but I can't be bothered as it is a literal
expr factorial(4)