.EQ delim @@ .EN .so eqnfix .na .fi .Lc Data Types in MACSYMA 2 .pp This chapter describes the data types used by ma . OUtline: Constants Numbers integers rational float bigfloat complex constant symbols boolean pi, e, ... strings file names indeterminates variables functions expressions general mathematical representation operators, operands, parsing CRE form Poisson form matrices lists , $fun, or $fun functions (sec. $ref) to kill an array element or the entire array, the associated function will never be called a second time on the same arguments. Thus the user should be aware that even if he redefines the associated function, those values which already exist will stay around. Of course individual array elements can be changed by assignment at any time. These associated functions are defined with the := operator. Their definition looks exactly the same as ordinary function definitions, except that the parameters in the left side of the definition are enclosed in brackets instead of parentheses. In order to use a subscripted variable as a single entity without it being an array and without ever assigning a value to it, it should be prefixed by an apostrophe to avoid it being confused with a non-subscripted variable of the same name. For example SUBST(0,W,W+'W[0]). The MACSYMA variable $var is a list of all the arrays that have been allocated, both declared and undeclared. $fun $see may be used to display the definition of an array associated function. $fun $see may be used to find out whether an array is declared or undeclared, how large it is, how many subscripts it has, and which elements have values in the case of an undeclared array. .Eb (C1) A[N]:=N*A[N-1]$ (C2) A[0]:1$ (C3) A[5]; (D3) 120 (C4) A[N]:=N$ (C5) A[6]; (D5) 6 (Note that the definition in C4 is being used because A[6] has no value up to this time.) (C6) A[4]; (D6) 24 (Since A[4] was assigned a value as a result of A[5] being computed, the new definition is not used.) .Ee If one is going to define a recursive function which is to be called several times then if may be more efficient to use an array with an associated function for initialization. The reason is that once an element is computed it is stored and thus need not be computed again whereas with a non-subscripted function, each recursive call may cause a repeat of a past computation. .sh 2 "Lambda Notation *" .pp Note that this section has an asterisk: avoid on first reading. .pp Lambda* .(f * Blame it on the logician A. Church, and John McCarthy who picked this up for programming languages. .)f notation provides a convention for establishing correspondence between the formal and actual parameters of a function, and the function "body" to be evaluated. Lambda notation is useful in ma primarily in construction and use of "anonymous" un-named functions for use in limited circumstances. It can also be used by the purist to define functions by creating lambda-expressions, and giving them names! .Eb (c1) f:lambda([x,y,z],r(x^2)+s(y^2)+v(z^2)); .EQ (d1) size -2 { lambda ( [ x , y, z ] , v ( z sup 2 )~+~ s ( y sup 2 ) ~+~ r (x sup 2 )) } .EN (c2) f(1,2,a); .EQ (d2) FIX THIS UP .EN .Ee ma also permits operators to be used in a functional notation; however, in order not to get a syntax error they must be surrounded by "s. .Eb (C3) "+"(1,2,A); (D3) A + 3 .Ee MOVE THIS TO NEXT CHAPTER .subsec ("Subscripted Functions (Arrays of Functions)",subscripted!functions,1) It is possible for the value of an array element to be a lambda expression. Thus if the assignment F[1]:LAMBDA([X],X^2+1) were performed, then F[1] could be used in the ordinary prefix functional sense with its arguments following in parentheses, e.g. F[1](3) would yield the value 10. There is an alternative syntax available for assigning a lambda expression to an array which introduces the notion of a "subscripted function". In the above case one could also type F[1](X):=X^2+1 and this would be entirely equivalent. Other elements of the array could be assigned different lambda expressions (or any MACSYMA expressions). If there is an algorithm for computing the different functions to be stored in an array on the basis of the subscripts alone, then one may use an associated function. For example, F[K]:=LAMBDA([X],X^K+1). Again an alternative syntax of F[K](X):=X^K+1 may be used. The left side of the definition consists of the function name followed by the subscripts, enclosed in brackets, followed by the arguments, enclosed in parentheses. The subscripts (which are not evaluated at definition time) must be either all numeric or all symbolic. Note that subscripted functions are treated exactly like arrays so all of the information in sec. $ref applies. In particular when a subscripted function is referenced, the element is immediately retrieved and applied to its arguments if it exists; otherwise it is computed (this time only) and then applied. Consequently, two evaluations of the definition are performed. Thus consider the definition F[K](E):=COEFF(E,X,K) and the call F[2](3*X^2-1). Although the user may have thought that this would return the coefficient of X^2 in 3*X^2-1, i.e. 3, it will return 0. The reason is that F[2] is first computed by evaluating the definition yielding 0, since E has not been bound at this time. Note that F[K](E):= SUBST(K,'J,'(COEFF(E,X,J))) would return the desired result as would F(K,E):=COEFF(E,X,K). Thus the user should be clear about the distinction between subscripted functions (a type of array) and ordinary functions. Also a subscripted function should not be redefined without $fun'ing or $fun'ing it first; otherwise the elements which have already been stored will be used. The $var list $see also includes subscripted functions. The function $fun $see may also be used on subscripted functions. .example (C1) T[N](X):=RATSIMP(2*X*T[N-1](X)-T[N-2](X))$ .scon 1This generates the Chebyshev polynomials.* .scon (C2) T[0](X):=1$ (C3) T[1](X):=X$ (C4) T[4](Y); .begin group 4 2 (D4) 8 Y - 8 Y + 1 .end (C5) G[N](X):=SUM(EV(X),I,N,N+2)$ (C6) H(N,X):=SUM(EV(X),I,N,N+2)$ .BEGIN GROUP (C7) G[2](I^2); 2 (D7) 3 I (C8) H(2,I^2); (D8) 29 .end .end .scon The following illustrates a definition for the Legendre polynomials. .example (C9) P[N](X):=RATSIMP(1/(2^N*N!)*DIFF((X^2-1)^N,X,N))$ (C10) Q(N,X):=RATSIMP(1/(2^N*N!)*DIFF((X^2-1)^N,X,N))$ .BEGIN GROUP (C11) P[2]; 2 3 X - 1 (D11) LAMBDA([X], --------) 2 (C12) P[2](Y+1); 2 3 (Y + 1) - 1 (D12) -------------- 2 .END .BEGIN GROUP (C13) Q(2,Y+1); 2 3 Y + 6 Y + 2 (D13) -------------- 2 .END (C14) P[2](5); (D14) 37 .begin group (C15) Q(2,5); 5 attempt to differentiate wrt a number .end .end .subsec (Additional Information About Functions,functions!continued,1) In order to pass a function as an argument to another function you need only give its name in the argument list of the call. It may then be used in the called function by following the name of the corresponding formal parameter with a parenthesized list of arguments. Subscripted functions $see are passed by giving the name followed by the subscripts in brackets. Arrays can be passed by giving the name of the array in the argument list and they can be referenced by subscripting the corresponding formal parameter. When passing names of functions or arrays one must take care that there is no atomic variable with the same name which is bound because then that value rather than the name will be passed. In this case the name should be preceded by a ' $see to prevent it from being evaluated. In order to assign to a formal parameter of a function so that the corresponding actual parameter gets changed (and remains changed) when the function is exited, then the :: operator rather than the : operator should be used. .example group (C7) F[I,J](X,Y):=X^I + Y^J; I J (D7) F (X, Y) := X + Y I, J (C8) G(FUN,ARG1,ARG2):=PRINT(FUN," APPLIED TO ",ARG1," AND ", ARG2," IS ",FUN(ARG1,ARG2))$ .begin group (C9) G(F[2,1],SIN(%PI),2*A); 2 LAMBDA([X,Y],Y+X ) APPLIED TO 0 AND 2 A IS 2 A (D9) 2 A .end .end .sh 2 Lists .pp Lists are representations for ordered sets of elements. These elements may be any ma expressions. The external representation is as a sequence of items separated by commas and enclosed in square brackets. An empty list is []. Many commands which must return a collection of answers use lists as the basis for the return value. .pp If the value of a variable is a list, its elements may be accessed for value, or changed, by using subscript notation. For example, .Eb (c1) l:[a,b,c,d]; .EQ (d1) size -2 { [a , b, c, d]} .EN (c2) l[3]:q$ (c3) l; .EQ (d3) size -2 { [ a , b, q , d ]} .EN .Ee .pp For certain commands,lists are used as a representation for mathematical vectors (row or column matrices). Lists are sometimes used as arguments to ma commands (e.g.\fImatrix, solve,\fP etc.). Operations on lists such as deleting elements, selecting an element, testing for membership in a list, and so on, are give in section ??. Because lists provide a model for ordered n-tuples, and lists of lists (etc.) are acceptable structures, they are very general. The Lisp programming language underlying ma uses this notion very heavily. .sh 2 Matrices .pp A matrix is a set of elements in a rectangular indexed arrangement. The index sets are integers beginning at 1. It is represented internally using a list of lists. By convention, the top level of lists are "rows", and each row is of the same length (the number of columns). Matrices may be constructed by using the function .Lf matrix "'row1_list, ['row2_list, ... ]" .We row1_list etc are lists of the same length. .Re a matrix .No you should give the matrix a name by assignment, or use the linelabel. .Ex m:matrix([a,b],[c,d]) .pp The functions .I entermatrix and .I genmatrix may also be used to construct a matrix. See section ?? on matrix functions. .PP THIS GOES TO NEXT CHAPTER The operators + , - , * , and / may be used between two matrices and take effect elementwise. (A matrix minus itself gives the zero matrix of the same size.) They may also be used between a scalar* and a matrix and the scalar will be operated on with each element of the matrix. .(f *In ma a scalar is an expression consisting of numbers, constants, and atoms declared scalar. .)f .pp Matrix multiplication is signified by using the dot operator (non-commutative product). Raising a matrix to a power (multiplying it by itself) is accomplished by use of the ^^ operator. That is, M.M is equivalent to M^^2. The inverse of a matrix may be obtained by using a negative exponent, i.e. M^^-1. If the switch $var is TRUE then .ip 1. Lists will behave arithmetically: they can be added to one another, etc. .ip 2. In matrix operations they can be used as row or column vectors and will be converted to such when necessary. An element of a matrix may be referenced by subscripting the matrix as with arrays but the same name should not be used to stand for both a matrix and an array, or the array use will take precedence. There are many functions for operating on matrices as well as many options which can be set to give the user much flexibility and control over matrix operations (these are described in sec. $ref). If a matrix is too wide to be displayed all at once, it is displayed column by column or as a list of lists. .example (C1) M:MATRIX([A,0],[B,1]); .begin group [ A 0 ] (D1) [ ] [ B 1 ] .end (C2) M[1,1]*%; .begin group [ 2 ] (D2) [ A 0 ] [ ] [ A B A ] .end (C3) M*M; .begin group [ 2 ] [ A 0 ] (D3) [ ] [ 2 ] [ B 1 ] .end (C4) M.M; .begin group [ 2 ] (D4) [ A 0 ] [ ] [ A B + B 1 ] .end (C5) D2-D4+1; .begin group [ 1 1 ] (D5) [ ] [ 1 - B A ] .end (C6) M^-1; Division by 0 .begin group (C7) M^^-1; [ 1 ] [ - 0 ] [ A ] (D7) [ ] [ B ] [ - - 1 ] [ A ] .end (C8) [X,Y].M; (D8) [ B Y + A X Y] .end .sec (Equations) An equation is formed in MACSYMA simply by using an equal sign between any two expressions. Equations may be added or subtracted, and they may be multiplied or divided by any expression. They may be operated on just as any MACSYMA expression can be and may serve as arguments to functions. .example (C1) X+1=Y^2$ (C2) X-1=2*Y+1$ (C3) D1+D2; .begin group 2 (D3) 2 X = Y + 2 Y + 1 .end (C4) D1/Y; .begin group X + 1 (D4) ----- = Y Y .end (C5) 1/%; .begin group Y 1 (D5) ----- = - X + 1 Y .end .end .sec (IF Statement,if!statement,1) The $fun statement is used for conditional execution. The syntax is .begin turn on "_" _IF 2condition* THEN 2expression1* ELSE 2expression2*. .end .scon The result of an IF statement is 2expression1* if 2condition* is true and 2expression2* if it is false. 2expression1* and 2expression2* are any MACSYMA expressions (including nested IF statements), and 2condition1 is an expression (known as a "predicate") which evaluates to TRUE or FALSE and is composed of relational and logical operators which are as follows: .example group turn on "\"; narrow 8; tabs 4, 24, 32, 36, 48, 56; \1Operator name\Symbol\\Type \greater than\>\\relational infix \equal to\= , EQUAL\" " \not equal to\#\\" " \less than\<\\" " \greater than\>= or equal to\\\" " \less than\<= or equal to\\\" " \and\AND\\logical infix \or\OR\\" " \not\NOT\\logical prefix .end The relational operators all have equal priorities which are less than the priorities of the arithmetic operators and greater than that of the logical operators. The priority of NOT is greater than that of AND which is greater than that of OR. The difference between "=" and EQUAL is discussed in sec. $ref. If the ELSE clause is omitted, this will be the same as if ELSE FALSE were specified. In order to have several expressions evaluated after the THEN or ELSE clauses, the expressions may be enclosed in a compound statement $see but care should be taken to return the desired value. The switch $var determines the action taken if a clause is not universally true or universally false $see. .example (C1) FIB[N]:= IF N=1 OR N=2 THEN 1 ELSE FIB[N-1]+FIB[N-2]$ (C2) FIB[1]+FIB[2]; (D2) 2 (C3) FIB[3]; (D3) 2 (C4) FIB[5]; (D4) 5 (C5) ETA(MU,NU):= IF MU=NU THEN MU ELSE IF MU>NU THEN MU-NU ELSE MU+NU$ (C6) ETA(5,6); (D6) 11 (C7) ETA(ETA(7,7),ETA(1,2)); (D7) 4 (C8) IF NOT 5>=2 AND 6<=5 OR 4+1>3 THEN A ELSE B; (D8) A .end .sec (Compound Statements,compound!statement,1) In order to execute a sequence of statements in a context where a single statement is permitted then the user may group these statements into a 2compound statement1 by separating them with commas and enclosing the whole group in parentheses. The value of a compound statement is the value of the last statement in the group. Compound statements are also useful for grouping together a sequence of related calculations when a computation cannot easily be expressed in a single MACSYMA statement. .example group (C1) IF X=Y THEN (X:X+1, Y:Y-1) ELSE (S:0, FOR I:1 THRU X DO (S:S+F(I), Y:Y-G(Y)))$ .end .sec (Program Blocks,program!blocks,1) Blocks in MACSYMA are somewhat analogous to subroutines in FORTRAN or procedures in ALGOL or PL/I. Blocks are like compound statements but also enable the user to tag statements within the block and to assign "dummy" variables to values which are local to the block. The syntax is: .inline function(BLOCK,|[v1, ... vk], statement1,..., statementj|) .scon where the 2vi* are atomic variables, possibly with initial assignments (see below) which are local to the BLOCK and the 2statements* are any MACSYMA expressions. If no variables are to be made local then the list may be omitted. A block uses these local variables to avoid conflict with variables having the same names used outside of the block (i.e. global to the block) and to free up storage used by local computation upon exit from the block. In this case, upon entry to the block, the global values are saved onto a stack and are inaccessible while the block is being executed. The local variables then are unbound so that they evaluate to themselves. They may be bound to arbitrary values within the block but when the block is exited the saved values are restored to these variables. The values created in the block for these local variables are lost. Where a variable is used within a block and is not in the list of local variables for that block it will be the same as the variable used outside of the block. In order to save and restore other local properties besides VALUE, namely ARRAY (except for complete arrays - $see), FUNCTION, DEPENDENCIES, ATVALUE, MATCHDECLARE, ATOMGRAD, CONSTANT, SCALAR and NONSCALAR$$All of these properties except for FUNCTION are related more closely to the use of the name as a variable rather than as a function.* $see, the function $fun should be used inside of the block with arguments being the names of the variables $see. The value of the block is the value of the last statement or the value of the argument to the function $fun which may be used to exit explicitly from the block. The function $fun may be used to transfer control to the statement of the block that is tagged with the argument to GO. To tag a statement, precede it by an atomic argument as another statement in the BLOCK. For example: BLOCK([X],X:1,LOOP,X:X+1,...,GO(LOOP),...). The argument to GO must be the name of a tag appearing within the BLOCK. One cannot use GO to transfer to a tag in a BLOCK other than the one containing the GO. Blocks typically appear on the right side of a function definition but can be used in other places as well. .example .begin group (C1) HESSIAN(F):=BLOCK([DFXX,DFXY,DFXZ,DFYY,DFYZ,DFZZ], DFXX:DIFF(F,X,2),DFXY:DIFF(F,X,1,Y,1), DFXZ:DIFF(F,X,1,Z,1),DFYY:DIFF(F,Y,2), DFYZ:DIFF(F,Y,1,Z,1),DFZZ:DIFF(F,Z,2), DETERMINANT(MATRIX([DFXX,DFXY,DFXZ],[DFXY,DFYY,DFYZ], [DFXZ,DFYZ,DFZZ])))$ .end (C2) HESSIAN(X^3-3*A*X*Y*Z+Y^3); .begin group 3 2 3 2 3 (D2) - 54 A X Y Z - 54 A Y - 54 A X .end (C3) SUBST(1,Z,QUOTIENT(%,-54*A^2)); .begin group 3 3 (D3) X + A Y X + Y .end .end The above example computes the Hessian of a cubic curve (the Folium of Descartes) which turns out to be invariant under this transformation, i.e. the result is of the same form. The example below illustrates the saving and restoring of values described at the beginning of this section. .example (C4) F(X):=BLOCK([Y], LOCAL(A), Y:4, A[Y]:X, DISPLAY(A[Y]))$ (C5) Y:2$ (C6) A[Y+2]:0$ (C7) F(9); .begin group A = 9 4 .end (D7) DONE (C8) A[Y+2]; (D8) 0 .once fill indent 0,0 1If LOCAL(A) had not been used, the value on line D8 would have been 9. .end .sec (The DO Statement,do!statements,1) The $fun statement is used for performing iteration. Due to its great generality the DO statement will be described in two parts. First the usual form will be given which is analogous to that used in several other programming languages (FORTRAN, ALGOL, PL/I, etc.); then the other features will be mentioned. .subsec (Commonly Used Forms,common!forms,1) There are three variants of this form that differ only in their terminating conditions. They are: .skip 1 .BEGIN GROUP NOFILL INDENT 0 1(a) 5$fun 2variable : 2initial-value 5STEP 2increment 5THRU 2limit 5DO 2body (b) 5FOR 2variable : 2initial-value 5STEP 2increment 5WHILE 2condition 5DO 2body (c) 5FOR 2variable : 2initial-value 5STEP 2increment 5UNLESS 2condition 5DO 2body1 .once fill indent 0,0 (Alternatively, the STEP may be given after the termination condition or limit. ) .end The 2initial-value*, 2increment*, 2limit*, and 2body* can be any expressions. To iterate over several statements, the 2body* can be made into a compound statement $see or a $fun $see. The 2condition* (or predicate) is as in the IF statement. If the 2increment* is 1 then "STEP 1" may be omitted. The execution of the DO statement proceeds by first assigning the 2initial-value* to the 2variable* (henceforth called the control-variable). Then: (1) If the control-variable has exceeded the 2limit* of a THRU specification, or if the 2condition* of the UNLESS is TRUE, or if the 2condition* of the WHILE is FALSE then the DO terminates. (2) The 2body* is evaluated. (3) The 2increment* is added to the control-variable. The process from (1) to (3) is performed repeatedly until the termination condition is satisfied. One may also give several termination conditions in which case the DO terminates when any of them is satisfied. In general the THRU test is satisfied when the control-variable is greater than the 2limit* if the 2increment* was non-negative, or when the control-variable is less than the 2limit* if the 2increment* was negative. The 2increment* and 2limit* may be non-numeric expressions as long as this inequality can be determined. However, unless the 2increment* is syntactically negative (e.g. is a negative number) at the time the DO statement is input, ma assumes it will be positive when the DO is executed. If it is not positive, then the DO may not terminate properly. Note that the 2limit*, 2increment*, and termination 2condition* are evaluated each time through the loop. Thus if any of these involve much computation, and yield a result that does not change during all the executions of the 2body*, then it is more efficient to set a variable to their value prior to the DO and use this variable in the DO form. The value normally returned by a DO statement is the atom DONE, as every statement in MACSYMA returns a value. However, the function $fun $see may be used inside the body to exit the DO prematurely and give it any desired value. Note however that a $fun within a DO that occurs in a $fun will exit only the DO and not the BLOCK. Note also that the $fun function may not be used to exit from a DO into a surrounding $fun. The control-variable is always local to the DO and thus any variable may be used without affecting the value of a variable with the same name outside of the DO. The control-variable is unbound (or resumes its global value, if any) after the DO terminates. .example (C1) FOR A:-3 THRU 26 STEP 7 DO LDISPLAY(A)$ (E1) A = -3 (E2) A = 4 (E3) A = 11 (E4) A = 18 (E5) A = 25 .once fill indent 0,0 1The function LDISPLAY generates intermediate labels; DISPLAY does not.* .SCON (C6) S:0$ (C7) FOR I:1 WHILE I<=10 DO S:S+I; (D7) DONE (C8) S; (D8) 55 .once fill indent 0,0 1Note that the condition in C7 is equivalent to UNLESS I > 10 and also THRU 10* .SCON (C9) SERIES:1$ (C10) TERM:EXP(SIN(X))$ (C11) FOR P:1 UNLESS P>7 DO (TERM:DIFF(TERM,X)/P, SERIES:SERIES+SUBST(X=0,TERM)*X^P)$ (C12) SERIES; .begin group 7 6 5 4 2 (D12) X X X X X -- - --- - -- - -- + -- + X + 1 96 240 15 8 2 .end .end .bcon 1which gives 8 terms of the Taylor series for e^[sin(x)].* .example (C13) POLY:0$ .begin group (C14) FOR I:1 THRU 5 DO FOR J:I STEP -1 THRU 1 DO POLY:POLY+I*X^J$ .end (C15) POLY; .begin group 5 4 3 2 (D15) 5 X + 9 X + 12 X + 14 X + 15 X .end (C16) GUESS:-3.0$ .begin group (C17) FOR I:1 THRU 10 DO (GUESS:SUBST(GUESS,X,.5*(X+10/X)), IF ABS(GUESS^2-10)<.00005 THEN RETURN(GUESS)); .end (D17) - 3.1622807 .end This example computes the negative square root of 10 using the Newton-Raphson iteration a maximum of 10 times. Had the convergence criterion not been met the value returned would have been "DONE". .subsec (Additional Forms of the DO Statement,additional!do,1) Instead of always adding a quantity to the control-variable one may sometimes wish to change it in some other way for each iteration. In this case one may use "NEXT 2expression*" instead of "STEP increment". This will cause the control-variable to be set to the result of evaluating 2expression* each time through the loop. .example group (C1) FOR COUNT:2 NEXT 3*COUNT THRU 20 DO DISPLAY(COUNT)$ COUNT = 2 COUNT = 6 COUNT = 18 .end As an alternative to $fun variable:value ...$fun... the syntax .skip once nofill center FOR variable FROM value ...DO... .end continue may be used. This permits the "FROM value" to be placed after the step or next value or after the termination condition. If "FROM value" is omitted then 1 is used as the initial value. Sometimes one may be interested in performing an iteration where the control-variable is never actually used. It is thus permissible to give only the termination conditions omitting the initialization and updating information as in the following example to compute the square-root of 5 using a poor initial guess. .example group (C1) X:1000 (C2) THRU 10 WHILE X#0.0 DO X:.5*(X+5.0/X)$ (C3) X; (D3) 2.236068 .end If it is desired one may even omit the termination conditions entirely and just give "DO body" which will continue to evaluate the body indefinitely. In this case the function $fun $see should be used to terminate execution of the DO. .example .begin group (C1) NEWTON(F,GUESS):=BLOCK([NUMER,Y],LOCAL(DF),NUMER:TRUE, DEFINE(DF(X),DIFF(F(X),X)), DO (Y:DF(GUESS), IF Y=0.0 THEN ERROR( "DERIVATIVE AT",GUESS," IS ZERO"), GUESS:GUESS-F(GUESS)/Y, IF ABS(F(GUESS))<5.0E-6 THEN RETURN(GUESS)))$ .end (C2) SQR(X):=X^2-5.0$ (C3) NEWTON(SQR,1000); (D3) 2.236068 .end (Note that RETURN, when executed, causes the current value of GUESS to be returned as the value of the DO. The $fun is exited and this value of the DO is returned as the value of the BLOCK because the DO is the last statement in the block.) One other form of the $fun is available in MACSYMA. The syntax is: .example once center 5FOR 2variable 5IN 2list [end-tests] 5DO 2body .end 1 The members of the 2list* $see are any expressions which will successively be assigned to the variable on each iteration of the 2body*. The optional 2end-tests* can be used to terminate execution of the DO; otherwise it will terminate when the 2list* is exhausted or when a RETURN is executed in the 2body*. (In fact, 2list* may be any non-atomic expression, and successive parts are taken.) .example (C1) FOR F IN [LOG, RHO, ATAN] DO LDISP(F(1.0))$ (E1) 0 (E2) RHO(1) %PI (E3) --- 4 (C4) EV(E3,NUMER); (D4) 0.78539816 .end .sec (Syntax Extension,syntax!extension,1) It is possible to add new operators to MACSYMA (infix, prefix, postfix, unary, or matchfix with given precedences), to remove existing operators, or to redefine the precedence of existing operators. Details may be found in Appendix II.