Discussion:
Passing functions as parameters
Jorge Calvo
2012-07-05 19:36:08 UTC
Permalink
Hello there:

I am trying to define a function which would take the name of another function as a parameter and use it somehow. My goal is to implement the bisection, secant, and Newton's method procedures, but at the moment I am trying to understand the proper syntax that will be needed in all of these methods. As a very simple example, I tried:

(%i1) testfun(f, a) := f(a) $

This works as long as f(x) is not defined globally:

(%i2) testfun(sin, 3.0);
(%o2) .1411200080598672

However, if f(x) is defined globally, then my testfun uses the global function and not the one indicated by the parameter:

(%i3) f(x) := x^2 - x $

(%i4) testfun(sin, 3.0);
(%o4) 6.0

I have fixed this by using apply instead:

(%i5) testfun(f, a) := apply(f, [a]) $

(%i6) testfun(sin, 3.0);
(%o2) .1411200080598672

However, I wonder if this is the best way to do this. Is there a way to pass a function (rather than just its name) as an argument?

Thanks in advance!

Jorge
--
Dr. Jorge Alberto Calvo
Associate Professor of Mathematics
Department of Mathematics and Physics
Ave Maria University

Phone: (239) 280-1608
Email: ***@avemaria.edu
Web: http://sites.google.com/site/jorgealbertocalvo
Richard Fateman
2012-07-05 22:31:14 UTC
Permalink
On 7/5/2012 12:36 PM, Jorge Calvo wrote:
> Hello there:
>
> I am trying to define a function which would take the name of another function as a parameter and use it somehow.
There is a newton iteration ; try load(newton1);
It looks like this..

newton(exp,var,x0,eps):=
block([xn,s,numer],
numer:true,
s:diff(exp,var),
xn:x0,
loop, if abs(subst(xn,var,exp))<eps then return(xn),
xn:xn-subst(xn,var,exp)/subst(xn,var,s),
go(loop) )$

so it is using expressions and subst, rather than functions.

> My goal is to implement the bisection, secant, and Newton's method procedures, but at the moment
....

using apply is fine.

You can pass a function like this, too..

w: lambda([x], sin(x)^2*exp(x)

and pass it to your functions. apply will still work.

Some people use funny names for parameters and hope for the best...
e.g.

secant(%%f, ....) := $$f(x)....
Richard Fateman
2012-07-05 22:41:07 UTC
Permalink
On 7/5/2012 3:31 PM, Richard Fateman wrote:
secant(%%f, ....) := %%f(x)...
^^ .

>
Barton Willis
2012-07-06 00:01:06 UTC
Permalink
The apply method has problems too:

(%i12) testfun(f, a) := apply(f,[a]) $
(%i13) testfun(a,1);
apply: found a evaluates to 1 where a function was expected.

Once again you are stuck with using goofy and difficult to read names and hoping for the best:

(%i16) testfun(%f, %x) := apply(%f,[%x]) $

(%i17) testfun(a,1);
(%o17) a(1)

If the lambda form method appeals to you, but lambda is too verbose, try:

http://www.math.utexas.edu/pipermail/maxima/2012/028437.html

Or you can give up and pass a formula and variable instead of a function.


--Barton
Robert Dodier
2012-07-06 01:29:56 UTC
Permalink
On 2012-07-06, Barton Willis <***@unk.edu> wrote:

> The apply method has problems too:
>
> (%i12) testfun(f, a) := apply(f,[a]) $
> (%i13) testfun(a,1);
> apply: found a evaluates to 1 where a function was expected.

Or enclose testfun in a lexical block --

blex ([f, a], testfun (f, a) := f (a));

f (x) := 1 + x;
g (x) := 1 - x;
testfun (g, 1);
=> 0
testfun (a, 1);
=> a(1)

I am inclined to give variables lexical rather than dynamic scope in
general. I suspect changing the scope policy wouldn't affect much user
code, and it would prevent a lot of annoying problems.

FWIW

Robert Dodier

PS. a simplistic lexical block implementation. I wouldn't be surprised
if there were a better way to do it.

(defmspec $blex (x)
(let*
((args (cdr x))
(vars (cdr (car args)))
(exprs (cdr args))
(gensym-vars (mapcar #'(lambda (s) (let ((s1 (gensym))) (setf (get
s1 'reversealias) (or (get s 'reversealias) s)) s1)) vars))
(subst-eqns (mapcar #'(lambda (x y) `((mequal) ,x ,y)) vars
gensym-vars))
(gensym-mprogn ($psubstitute `((mlist) ,@subst-eqns) `((mprogn)
,@exprs))))
(meval gensym-mprogn)))
Robert Dodier
2012-07-06 01:20:43 UTC
Permalink
On 2012-07-05, Jorge Calvo <***@avemaria.edu> wrote:

> I am trying to define a function which would take the name of another
> function as a parameter and use it somehow.

> However, if f(x) is defined globally, then my testfun uses the global
> function and not the one indicated by the parameter:

Maxima's treatment of array and function names has always driven me
crazy. It ought to be consistent; either always using the value, or
never. I vote for always.

> I have fixed this by using apply instead:

Yes, that's a suitable solution.

best

Robert Dodier
Loading...