The script below contains a few commands that illustrate the idea compactly:
- You can define a function of x via [func $expression]
- You can define the derivative of that function via [deriv funcname]
- You can get the value of a function for a specific value
# functions.tcl -- # # Package for analysing real functions # (sample Workbench module) # # Notes: # This package provides basic analysis functionality for real # functions of one variable. # # Version information: # version 0.1: initial implementation, july 2002 package provide Functions 0.1 namespace eval ::Workbench { variable nextID 0 # uniqueID -- # Create a unique ID (private) # # Arguments: # expression Expression using "x" as independent variable # evaluating to the function value # # Result: # Name of a new command implementing the function # # Side effect: # Create a new command that takes one argument, x, and # returns the function value # proc uniqueID {typename} { variable nextID incr nextID return "${typename}##$nextID" } } ;# End of namespace namespace eval ::Functions { namespace export func deriv # func -- # Create a new function # # Arguments: # expression Expression using "x" as independent variable # evaluating to the function value # # Result: # Name of a new command implementing the function # # Side effect: # Create a new command that takes one argument, x, and # returns the function value # proc func {expression} { set name [::Workbench::uniqueID "X-FUNCTION"] interp alias {} $name {} [namespace current]::xfunc_impl $expression return $name } # xfunc_impl -- # Implementation of an "x function" # # Arguments: # expression Expression using "x" (hidden via [interp alias]) # x Independent variable # # Result: # Function value # proc xfunc_impl {expression x} { expr $expression } # deriv -- # Create a new function that evaluates to the derivative of the given # function # # Arguments: # funcname Name (!) of the function # step Step for the numerical derivation # # Result: # Name of a new command implementing the function's derivative # # Side effect: # Create a new command that takes one argument, x, and # returns the original function's derivative # proc deriv {funcname {step 0.01} } { upvar $funcname fname set name [::Workbench::uniqueID "X-DERIVATIVE"] set expression [lindex [interp alias {} $fname] 1] interp alias {} $name {} [namespace current]::xderiv_impl $fname [expr {$step*0.5}] return $name } # xderiv_impl -- # Implementation of the derivative of an "x function" # # Arguments: # fname Name (!) of the function # step Step size for numerical derivation # xv Independent variable # Result: # Value of derivative # # Note: # By using the # proc xderiv_impl {fname step xv} { set x [expr {$xv-$step}] set fx1 [$fname $x] set x [expr {$xv+$step}] set fx2 [$fname $x] expr {($fx2-$fx1)/(2.0*$step)} } } ;# End of namespace # # Import the functions procedures # namespace import ::Functions::* # # Simple demo # if { [file tail [info script]] == [file tail $::argv0] } { puts "Simply a parabola: y = x^2" set f [func {$x*$x}] set df [deriv f] set x 0.0 while { $x < 10.1 } { puts "[$f $x] [$df $x]" set x [expr {$x+1.0}] } puts "A more complex function" set f [func {sin($x)*$x}] set df [deriv f] set x 0.0 while { $x < 10.1 } { puts "[$f $x] [$df $x]" set x [expr {$x+0.1}] } }