[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> &lt;<a href=3D"m=
ailto:robert.dodier at gmail.com">robert.dodier at gmail.com</a>&gt; 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>&nbsp;&nbsp;&nbsp; block( [op: op(expr)],<br>&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if op=3Dfalse then...&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 3, 3.0, 3.0b0, x<br>&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // but NOT 1/3, %pi/2=
, x[1]
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elseif op=3D&quot;+&qu=
ot; then ...&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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.&nbsp; Errors are a *good* thing in cases lik=
e this.&nbsp; 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>&nbsp;&nbsp;&nbsp; block( [op],<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; if mapatom(expr) then ...&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp; // 3, 3.0, 3.0b0, 1/3, %pi, x, x[1]<br>&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elseif (op:op(expr))=3D&quot;+&quot; the=
n ...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...)<br><br>or in more =
sophisticated code, probably something like
<br><br>&nbsp;&nbsp;&nbsp; block( [op],<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; if numberp(expr) then&nbsp; ...&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 3, 3.0, 3.0b0, 1/3<br>&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp; elseif constantp(expr) then ...&nbsp;&nbsp;&nbsp=
;&nbsp; // %pi, %pi/2<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elseif =
mapatom(expr) then ...&nbsp;&nbsp;&nbsp;&nbsp; // x, x[1]<br>&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp; ...)
<br><br>Alternatively, if you only want to handle a few operators, it might=
 be cleaner to define:<br><br>&nbsp;&nbsp;&nbsp;&nbsp; plusexprp(expr):=3D =
not(atom(expr)) and op(expr)=3D&quot;+&quot;<br><br>and use those.&nbsp; Ye=
s, there is a slight performance penalty....
<br><br>The main ugly thing in all this is the name &quot;mapatom&quot; (me=
aning something that 'map' treats as atomic).<br><br>Oh, and by the way, it=
 is probably a bad idea to use &quot;op&quot; in code in the first place, s=
ince its behavior is controlled by the global inpart flag.&nbsp; Much bette=
r to define inop(ex):=3Dblock([inflag:true],op(ex)), which is both more con=
sistent and much more efficient.&nbsp; By the way, did you know that op(3/4=
)=3Dinop(3/4)=3D&quot;//&quot;?&nbsp; Surprise!&nbsp; 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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -=
s<br><br></div></div>

------=_Part_2739_4918177.1147033126532--




More information about the Maxima mailing list