Looking a bit like Maple

Arjen Markus (8 may 2007) Some examples of Maple [1 ] code inspired me to consider the procedures below. The idea is simple: Suppose you want to compute a series:

            n      i i
    f(x) = Sum (-1) x /(i+1)**2
           i=0

You could write a procedure like this:

    proc f {x n} {
        set sum 0.0
        for { set i 0 } { $i <= $n } { incr i } {
            set sum [expr {$sum + pow(-$x,$i)/(($i+1)*($i+1))}]
        }
        return $sum
    }

but in a mathematical application like Maple, it makes more sense to provide a command that takes care of the details:

    f = series(n, i->(-x)^i/i^2);

(or something similar, I am not familiar with Maple, just saw some code fragments in an article)

The question arises: can we do that in Tcl too?

Well, that is easy (except for a few nasty details, as using a private namespace and a local variable with an uncommon name):

 namespace eval ::Maple {
     variable count 0
     namespace eval v {
     }
 }

 # series --
 #     Define a new function that evaluates a series
 #
 # Arguments:
 #     var          Names of the variables that holds the arguments
 #     number       number of terms
 #     idx          Index variable
 #     expression   Expression defining the terms
 #
 # Result:
 #     Name of a new procedure
 #
 proc ::Maple::series {var number idx expression} {
     variable count

     set procname ::Maple::v::series_$count
     incr count

     set numbern [lindex $number 0]
     puts "numbern  =$numbern"

     proc $procname [list $var $number] [string map \
         [list VAR $var IDX $idx NUMBER $numbern EXPR $expression] {
         set _sum_ 0.0
         for { set IDX 0 } { $IDX <= $NUMBER } { incr IDX } {
             set _sum_ [expr {$_sum_ + EXPR}]
         }
         return $_sum_
     }]

     return $procname
 }

Now let us try it:

 #
 # The direct definition
 #
 proc fdir {x {n 100}} {
     set sum 0.0
     for { set i 0 } { $i <= $n } { incr i } {
         set sum [expr {$sum + pow(-$x,$i)/(($i+1)*($i+1))}]
     }
     return $sum
 }

 set f [::Maple::series x {n 100} i {pow(-$x,$i)/(($i+1)*($i+1))}]

 set x 0.0
 while { $x < 0.99 } {
     puts "$x: [$f $x] - [fdir $x]"
     set x [expr {$x + 0.05}]
 }

I leave it as an exercise to expand this little package to other mathematical objects, such as matrices, vectors or definite integrals