Maple 2019 includes the following enhancements to the Maple language and programming facilities.
Maple Language
Two Variable for-in Loops
Maple's for-in loop iterates over a container (list, Array, etc.), setting the loop's control variable to the value of each element in turn:
> | for i in [a,b,c] do
print(i) end do; |
Usually, having just the element's value is sufficient, but sometimes its index into the container is also needed. The new two-variable form of the for-in loop makes this straightforward:
> | R:= LinearAlgebra:-RandomMatrix(3,4); |
> | for ind, val in R do
if val < 0 then R[ind] := -val end if end do: |
> | R; |
Using Assignments, if- statements, try- statements, and Loops in Expressions
It is now possible to use statements within expressions. The supported statements are: assignments, if-statements, try-statements, and all forms of loop-statements.
An assignment can be written within an expression by enclosing it in parentheses. The value of an assignment expression is the value that was assigned (that is, the evaluated right-hand side of the assignment).
> | x:=2: |
> | if x<>0 and (invx :=1/x) <1 then print(invx) end if: |
> | i:=2: |
> | do i until (i:=nextprime(i)) > 15; |
The if- and try- expressions can be written anywhere within an expression:
> | x:=-3; |
> | signedSqr := x* if x<0 then -x else x end if; |
The value of such an expression is the value of the last expression computed in a statement sequence within it (i.e. the value that % would have if the expression were evaluated as a statement).
Loop expressions must generally be enclosed in parentheses, except in a few unambiguous cases: as the sole entry in a list or set, or the entire right-hand side of an assignment or return statement.
> | N :=5; |
> | [for i to N do i end do]; |
> | sqrSeq := for i to N do i^2 end do; |
Unlike a loop-statement, the value of a loop expression is a sequence of the last values computed in each iteration of the loop.
Storage for the result of loop-expressions is allocated efficiently. In most cases, the amount of storage required can be determined in advance, so it is all pre-allocated. When it cannot be determined in advanced, it is grown in a way that is still O(N) in the number of iterations, instead of the O(N^2) cost when appending one element at a time.
Loop expressions make it easy to generate sequences whose length cannot be readily predetermined. For example, this generates a list of all primes less than some upper bound.
> | N:=100; |
> | [(i:=2), (while (i:= nextprime(i)) <N do i end do)] |
Note that input of these expression-statements is currently not supported by 2-D input in the Standard interface.
Increment, Decrement, and Assignment Operators
Maple now supports C-style increment, decrement, and assignment operators. Rather than having to write,
> | N := N+1; |
one can write,
> | N+=1; |
or:
> | ++N; |
Besides being shorter to type, in cases where N is expensive to compute, this is more efficient. Consider,
A[expensiveOperation()] := A[expensiveOperation()] + 3;
compared to:
A[expensiveOperation()] += 3;
In the latter, expensiveOperation() is called only once.
The increment and decrement operators, ++ and --, can be applied either before or after the value to be incremented or decremented. If applied before, then the result of expression is the new value. If applied after, the result is the previous value:
> | N := 1; |
> | a := ++N; |
> | b := N++; |
> | N; |
The assignment operators, like ordinary := assignments, can be used within an expression by enclosing the entire assignment in parentheses.
The complete set of assignment operators is:
+=, -=, *=, /=, mod=, ^=, .=, and=, or=, xor=, implies=,
union=, intersect=, minus=, and ,=
The last one, the `,=` operator, is special. In most cases, it constructs an expression sequence of the left and right-hand sides, assigning it to the left-hand side:
> | s := 1; |
> | s ,= 2, 3; |
> | s; |
However, when it is applied to one-dimensional Arrays or any object implementing a `,=` method, the right-hand side is appended to the container in-place:
> | A := Array([a,b,c]); |
> | refA := A; |
> | A ,= d: |
> | A, refA; |
Note that input of these assignment operators is currently not supported by 2-D input in the Standard interface.
Efficient Mutable Strings and the String Function
Strings in Maple are immutable. This makes them very efficient to use as values, but less efficient to manipulate.
> | a := "Hello"; b:= "world"; |
> | a := cat(a," ",b); |
After the above has executed, `a` has the value "Hello world", but the string "Hello" still exists in memory until the garbage collector dispose of it. Thus, the following is inefficient:
> | s := ""; |
> | for c from "a" to "z" do s := cat(s,c) end do: |
> | s; |
This successively produces the strings "a", "ab", "abc", etc., leaving each previous result to be cleaned up later.
Maple 2019 allows mutable strings to be represented as one-dimensional Arrays of 1-byte integers. Such an Array can be constructed explicitly,
> | s := Array([], datatype=integer[1]); |
or using the new notation:
> | s:= Array(""); |
The Array can also be constructed and initialized in a single call:
> | s := Array("Hello"); |
The `,=` assignment operator can be used to append to the Array, in-place:
> | s ,= " "; |
> | s ,= "world"; |
More than one item can be appended at once, including other such arrays:
> | question := Array("How are you?"); |
> | s ,= "! ", question, "\n"; |
The printf "%s" format understands these Arrays:
> | printf("The string: %s",s); |
The string: Hello world! How are you? |
The new String function can convert this back to a regular immutable string:
> | t := String(s); |
The String function can also convert and concatenate multiple arguments into a string:
> | s := Array("Hello"); |
> | String(s, " world! The answer is ", 7!/5!); |
Neutral Operators
The set of valid characters for symbolic neutral operators has been expanded. Previously, the allowable symbols after the initial "&" character were:
! " $ * + , - . / < = > ? @ \ ^ ~
Now, the first character after the "&" can also be one of these:
% & ' ( ) : ; [ ] ` { | }
The second and subsequent characters after the "&" can be from the original set, or these additional characters:
) ] | }
Neutral operators are usually left-associative:
> | a &x b &y c; |
If a neutral operator starts with "&&" and has at least one additional character, then it is right associative:
> | a &&x b &&y c; |
Note that input of the new neutral operators is currently not supported by 2-D input in the Standard interface.
Local Scoping
Maple 2019 removes the requirement that all procedure and module local and global variables, and module exported variables, be declared at the beginning of the procedure or module before any executable statement.
Declarations of exported variables can appear anywhere within the top-level statement sequence of a module, and global declarations can appear in any statement sequence within a procedure or module. Local variable declarations are even more flexible, and can appear as statements, within assignment expressions, and in the control variable specification of for-loops.
Variable declarations have a defined scope, and the same variable can be declared in more than one scope as long as the declarations are compatible, and one scope is not contained within the other.
This feature is not supported in 2-D input.
Miscellaneous
Operator procedures, defined using the arrow notation, may now have local variable declarations:
> | iota := n -> local i; (for i to n do i od): |
> | iota(5); |
Note that input of local variable declarations for operator procedures is currently not supported by 2-D input in the Standard interface.
The `in` membership test operator now works even if the member being tested evaluates to NULL:
> | n := 3; |
> | evalb(n in {1,2,3}); |
> | n := NULL; |
> | evalb(n in {1,2,3}); |
Previously, cases where the candidate might be NULL had to be protected like this:
> | evalb(n <> NULL and n in {1,2,3}); |
The `lprint` command can now be invoked with an optional index argument, [2], which will cause it to line-break any procedures that it prints. Unlike the output produced by the pretty-printer, which will attempt to pack several statements onto one line if an entire statement sequence fits, `lprint[2]` will line-break and indent in a completely consistent manner, and will not center the result on the screen:
> | f := proc(x,y) local a; if x < y then y-x else a := x-y; a^2 end if end proc; |
> | lprint[2](eval(f)); |
proc( x, y )
local a; if x < y then y-x; else |
a := x-y;
a^2; end if; end proc |
The "%a" and "%A" formats of the printf, sprintf, and fprintf functions can now be modified by the "Z" modifier, which instructs them to produce output equivalent to the `lprint[2]` output above. In conjunction with sprintf, this effectively allows lprinting to a string:
> | s := sprintf("%Za",eval(f)); |
New Commands
ArrayTools
> | with(ArrayTools): |
Partition
The Partition command partially sorts a data structure around a given order statistic.
> | v := [5, 2, 5, 2, 3, 4, 4, 5, 3, 1, 5, 2, 3, 2, 2, 4, 3, 3, 1, 2]: |
Partition can be used to find the third-smallest entry of v.
> | w := Partition(v, 3) |
> | w[3] |
We see that , so the third-smallest entry of is 2.
Remove
The Remove command removes entries and shrinks an Array.
> | A := Array([11, 22, 33, 44, 55]): |
Remove A[3] and shrink:
> | Remove(A, 3) |
Reverse
The Reverse command reverses the entries of a Matrix, Vector, or Array.
> | A := Array([1, 2, 3, 4]): |
> | Reverse(A) |
convert/english
The convert/english command is not new, but it now allows for round-tripping of integer to english conversions.
> | en := convert(-1234567890, 'english'); |
> | n := convert( en, 'english'); |
Download
The Download command now makes it possible to download data from a URL to a local file.
tablereverse
The tablereverse function takes a table and returns a new table that is a reversal of the initial table.
> | T := table(["apple" = "fruit", "orange" = "fruit", "zucchini" = "vegetable", "milk" = "dairy"]) |
> | tablereverse(T) |
Kernel Options
The kernelopts command has several new options:traceshowspecassign: boolean; If true, causes some assignments shown during tracing to appear in a distinctive way. The default is false.
Command Line Interface
New Interface Options
Several new options to the interface command have been introduced. These primarily affect the command-line interface:
The trailingsemicolon option, which is false by default, causes a semicolon to be printed after the last statement in each statement sequence when a procedure is printed (by lprint, print, or the "%a" printf format).
The compactdisplay option, which is true by default, tells the pretty-printer to pack multiple statements onto one line when they fit. If set to false, then multiple statements are usually printed on separate lines, the exception being when the entire single statement (e.g. an if-statement) containing the multiple statements fits on one line.
The existing errorbreak option, which controls what happens when Maple is reading a script of commands from a file, has a new allowed value of 3. This is equivalent to interface(errorbreak=2), meaning that reading should stop on any error, but has the additional effect of issuing a stack trace, as if the user had typed the tracelast command after the error occurred. This option can also be set by passing -e3 when invoking Maple from the system command line.
The echofile option tells Maple to echo all input and output of a session to a log file. The value of this option should be a string, specifying the name of the file. If the specified file name ends in ".html" or ".htm", the session is logged in HTML format, with syntax highlighting, otherwise it is logged as plain text. If an empty string or the string "none" is specified, echoing to a file is terminated. This option can be invoked from the very beginning of a session by using the --echofile=filename option when invoking Maple from the system command line.
Color Output
When used with a compatible terminal, Maple can now do color syntax highlighting for both output and user input. This new capability is controlled by the following interface options:
Option |
Description |
ansi=true or ansi=false |
Controls whether any form of highlighting is used at all. |
ansicolor=list, ansicolor=integer, ansicolor=[] |
Controls the choice of colors used. If set to a list, the list specifies the colors for different categories of output. An integer in the range of 0 to 6 selects one of several predefined color palettes. An empty list produces output that uses bold, italic, and underline
|
ansilprint=true or ansilprint=false |
Controls whether lprinted output is syntax highlighted. |
ansiedit=true or ansiedit=false |
Controls whether command-line input is syntax highlighted. |
showcolors |
Illustrates the current syntax highlight color palette. |
showtermcolors |
Shows what colors the terminal is capable of displaying. |
Color support is enabled by default if the current terminal is known to support it. It can be manually controlled using the interface options described above, or these can be put in the user's Maple initialization file.
Color support has also been extended to the character plot driver, which can be selected using interface(plotdevice=colorchar). See plot/device.
Likewise, the ImageTools:-Preview command can now produce color character output (color "ASCII art"), which is much more representative of the actual image than a monochrome character preview was.
Command History Manipulation
The command-line interface adds several new facilities for interactively manipulating, replaying, saving, and restoring the history of commands entered into Maple. Typing "!!?" at the Maple prompt will display a brief summary.
Debugger
The output of the showstat command has been improved with respect to the display of long lines, especially in-line procedures and statements that would previously display as one long unbroken line.
A new debugger command, edit, will open the source file containing the currently stopped procedure, at the line corresponding to the current statement. A corresponding Maple command, editsource(), will do the same for a specified procedure and statement number. Both require that the source code is available, and that kernelopts(keepdebuginfo) was set to true or Maple was started with the --keep-debug-info option on the system command line.
The help command in the debugger now displays a summarized version of the information on the debugger help page. An optional argument to the help command will display help for only those debugger commands for which the argument is a prefix (e.g. "help stop" will display help for stopat, stopwhen, etc.).
Mint
A new option for the stand-alone mint utility (normally used to find potential issues in Maple programs) now has an option to generate a "ctags" format file. This is a file that can be used by many text editors to find the implementation of a given procedure when a special key is pressed (or menu item invoked) on a call to that procedure. It was originally designed for the "C" programming language, but works equally well with other languages so long as there exists a tool to generate the tag file. The "-c" option to Mint, which should be followed by the desired name of the tag file, will do that for all the files it processes during one call. Typically, one would call mint on the top level module of a package, resulting in a tag file for the entire package.
In keeping with the theme of coloring command line output, mint can now also produce color output if the system environment variable MINT_COLORS is set appropriately. This is analogous to similar schemes used by Linux command line utilities such as grep (GREP_COLORS) or gcc (GCC_COLORS).