[Maxima] proposal to modify op and args
Stavros Macrakis
macrakis at alum.mit.edu
Sun May 7 15:18:46 CDT 2006
------=_Part_2739_4918177.1147033126532
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
On 5/7/06, Robert Dodier <robert.dodier at gmail.com> wrote:
>
> At present the functions op and args barf on atoms.
> I propose that op and args return false when the argument is an atom.
>
> This change is intended to obviate the need to always test whether
> the argument is an atom before calling op or args.
This does indeed make one use-case easier, namely a dispatch of the form:
block( [op: op(expr)],
if op=3Dfalse then... // 3, 3.0, 3.0b0, x
// but NOT 1/3, %pi/2,
x[1]
elseif op=3D"+" then ...
...)
However, it also makes it much easier to incorrectly assume that an
expression *has* an operator when it doesn't, and to propagate nonsense
further into the program. Errors are a *good* thing in cases like this.
For that matter, checking whether an expression is an atom is usually not
the right thing -- you want to check whether it is a symbolic constant or
variable, which may be subscripted, so the above code would become:
block( [op],
if mapatom(expr) then ... // 3, 3.0, 3.0b0, 1/3, %pi, x,
x[1]
elseif (op:op(expr))=3D"+" then ...
...)
or in more sophisticated code, probably something like
block( [op],
if numberp(expr) then ... // 3, 3.0, 3.0b0, 1/3
elseif constantp(expr) then ... // %pi, %pi/2
elseif mapatom(expr) then ... // x, x[1]
...)
Alternatively, if you only want to handle a few operators, it might be
cleaner to define:
plusexprp(expr):=3D not(atom(expr)) and op(expr)=3D"+"
and use those. Yes, there is a slight performance penalty....
The main ugly thing in all this is the name "mapatom" (meaning something
that 'map' treats as atomic).
Oh, and by the way, it is probably a bad idea to use "op" in code in the
first place, since its behavior is controlled by the global inpart flag.
Much better to define inop(ex):=3Dblock([inflag:true],op(ex)), which is bot=
h
more consistent and much more efficient. By the way, did you know that
op(3/4)=3Dinop(3/4)=3D"//"? Surprise! If we were designing from scratch, =
I
would *not* have op(x[1])=3Dx or op(3/4)=3D/, but I think those are importa=
nt
cases to keep backwards-compatible.
In all, it seems to me that it would be a classic design error to have op d=
o
anything other than give an error when it is passed inappropriate arguments=
.
-s
------=_Part_2739_4918177.1147033126532
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
On 5/7/06, <b class=3D"gmail_sendername">Robert Dodier</b> <<a href=3D"m=
ailto:robert.dodier at gmail.com">robert.dodier at gmail.com</a>> wrote:<div><=
span class=3D"gmail_quote"></span><blockquote class=3D"gmail_quote" style=
=3D"border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; p=
adding-left: 1ex;">
At present the functions op and args barf on atoms.<br>I propose that op an=
d args return false when the argument is an atom.<br><br>This change is int=
ended to obviate the need to always test whether<br>the argument is an atom=
before calling op or args.
</blockquote><div><br>This does indeed make one use-case easier, namely a d=
ispatch of the form:<br><br> block( [op: op(expr)],<br>&n=
bsp; if op=3Dfalse then... &=
nbsp; // 3, 3.0, 3.0b0, x<br> &nbs=
p; &=
nbsp; &nbs=
p; &=
nbsp; // but NOT 1/3, %pi/2=
, x[1]
<br> elseif op=3D"+&qu=
ot; then ... <br> &nbs=
p; ...)<br><br>However, it also makes it much easier to incorrectly assume =
that an expression *has* an operator when it doesn't, and to propagate nons=
ense further into the program. Errors are a *good* thing in cases lik=
e this. For that matter, checking whether an expression is an atom is=
usually not the right thing -- you want to check whether it is a symbolic =
constant or variable, which may be subscripted, so the above code would bec=
ome:
<br><br> block( [op],<br> &n=
bsp; if mapatom(expr) then ... &nb=
sp; // 3, 3.0, 3.0b0, 1/3, %pi, x, x[1]<br> &n=
bsp; elseif (op:op(expr))=3D"+" the=
n ...<br> ...)<br><br>or in more =
sophisticated code, probably something like
<br><br> block( [op],<br> &n=
bsp; if numberp(expr) then ... &nb=
sp; // 3, 3.0, 3.0b0, 1/3<br> &nbs=
p; elseif constantp(expr) then ...  =
; // %pi, %pi/2<br> elseif =
mapatom(expr) then ... // x, x[1]<br> &n=
bsp; ...)
<br><br>Alternatively, if you only want to handle a few operators, it might=
be cleaner to define:<br><br> plusexprp(expr):=3D =
not(atom(expr)) and op(expr)=3D"+"<br><br>and use those. Ye=
s, there is a slight performance penalty....
<br><br>The main ugly thing in all this is the name "mapatom" (me=
aning something that 'map' treats as atomic).<br><br>Oh, and by the way, it=
is probably a bad idea to use "op" in code in the first place, s=
ince its behavior is controlled by the global inpart flag. Much bette=
r to define inop(ex):=3Dblock([inflag:true],op(ex)), which is both more con=
sistent and much more efficient. By the way, did you know that op(3/4=
)=3Dinop(3/4)=3D"//"? Surprise! If we were designing =
from scratch, I would *not* have op(x[1])=3Dx or op(3/4)=3D/, but I think t=
hose are important cases to keep backwards-compatible.
<br><br>In all, it seems to me that it would be a classic design error to h=
ave op do anything other than give an error when it is passed inappropriate=
arguments.<br><br> -=
s<br><br></div></div>
------=_Part_2739_4918177.1147033126532--
More information about the Maxima
mailing list