 Data Type Coercion in Maple 16 - Maple Programming Help

Data Type Coercion in Maple 16

Coercion refers to the ability to pass one type of data to a procedure and have it receive a different type. The passed data is coerced or converted to the new type behind the scenes. The user of the procedure benefits by being able to use a larger variety of data types, which may all look alike. The author of the procedure benefits by being able to focus on handling only the best data type suited to the task.

/

Using Maple Package Commands: LinearAlgebra

There are various LinearAlgebra routines that expect Matrices for parameters. Before the introduction of data type coercion these routines would raise errors when given Arrays  or  lists. With data type coercion, these routines are now capable of accepting a wider range of inputs.

 >
 ${2}$ (1.1)
 >
 ${-}{2}$ (1.2)

Various other routines in Maple's library have been updated to make use of coercion. No knowledge of programming is necessary to make use of this new feature. Simply using the same commands will now work on a wider variety of data types.

Coercion could involve anything from changing integers to floats, or names to strings, or lists to matrices to name a few. The author of the target procedure can focus on dealing with one core data-structure, while leveraging parameter processing to allow other acceptable types to also be supported. Using data type coercion makes authoring code easier by declaring only the type you want and letting Maple take care of the conversions.

Declaring a Parameter that uses Coercion

 > p := proc( m::~Matrix )     whattype(m); end:

 ${\mathrm{Matrix}}$ (2.1)

 ${\mathrm{Matrix}}$ (2.2)

 ${\mathrm{Matrix}}$ (2.3)

Adding a ~ prefix to the m::~Matrix parameter specification in the example above tells Maple it will accept something similar to a Matrix. You can now pass in a Vector. Behind the scenes an $n$-element column vector will be coerced into a $n$x1 matrix. In this case, there is no conversion or data copying going on; rather, an alias, or different view on the same data, is applied. Hence the term "coercion", the data structure is coerced into the right form.

One important aspect of rtable to rtable coercion is that it provides a way to control the lower-bound options for Arrays. Maple allows the flexibility of using your choice of lower bound when an Array is declared, but it is often seen that code is not prepared to handle arrays that have their index starting at anything other than 1. Using coercion, you can specify that a 1-based Array is expected.

Standardizing Array Bounds

In this example the 2x2 array passed in had lower bounds of 2 and 6. During the calling of procedure 'p', an alias was created so that B has a new view on the data. Inside the procedure B can be used as an ordinary 1-based array.

 > p := proc( B::~Array(1..,1..) )     ArrayDims(B); end:

$\mathrm{ArrayDims}\left(A\right);$

 ${2}{..}{3}{,}{6}{..}{7}$ (3.1)

$p\left(A\right);$

 ${1}{..}{2}{,}{1}{..}{2}$ (3.2)

There are times when you may want something other than a 1-based array. For example, when translating code written in another language, like C, it might be easier if you use 0-based arrays. In the following example, M[0,0] is the first array element inside the procedure, while outside the procedure the caller can continue to use the default for Maple arrays and matrices. The coercion is done in the most efficient way possible, without copying the data.

 > p := proc( M::~Array(0..,0..) )     M[0,0]; end:

 ${1}$ (3.3)

Coercion in the examples above applies when, for a given type T, there exists a command, ~T.   Currently ~Array, ~Matrix, and ~Vector exist as top-level built-in procedures in Maple. You can add additional ~ commands as top-level commands or as module exports.

The following example shows how to declare a private coercion routine inside a module. The use of "ModuleApply" makes the module work the same way as a procedure, but because it is a module, other methods and data can be associated with it. The method highlighted in red declares the way floats will be converted to rationals. The method highlighted in blue uses the parameter r -- declared as coercible type ~rational. When this procedure is called with a float argument, the procedure body sees only the coerced rational.

 > Frac := module()     local ModuleApply, ~rational;     ~rational := proc( a::float ) convert(a,rational); end;     ModuleApply := proc( r::~rational ) frac(r); end; end module:

$\mathrm{Frac}\left(1.5\right);$

 $\frac{{1}}{{2}}$ (4.1)

$\mathrm{Frac}\left(\frac{3}{2}\right);$

 $\frac{{1}}{{2}}$ (4.2)

The long form of the coerce() parameter declaration lets you control exactly what types are candidates for coercion and how they will be coerced or converted. Inside the coerce() declaration will be a sequence of types and/or procedures. The procedures may be declared inline as "arrow" procedures, usually containing explicit types for each procedure.

Flexible Extended Syntax Using coerce()

Example:

A simple way to allow either a name or string as the first argument of the procedure, but only ever have to deal with the string form.

 > p := proc( s::coerce( string, (s::name)->convert(s,string) ) )     s; end:

This procedure accepts a single argument which gets returned unchanged. When this procedure is called given s as a string, it matches the first coercion, which is simply a type match to string. The return value is still a string -- the argument is passed through unchanged.

$p\left("a string"\right);$

 ${"a string"}$ (5.1)

When the same procedure is given s as a name, the second coercion s->convert(s,string) is applied. This is executed as inline code, and transforms the passed argument into a string. The return value here is also a string -- the parameter is changed before executing any code in the body of the procedure.

$p\left(\mathrm{a name}\right);$

 ${"a name"}$ (5.2)

If some other kind of argument is passed, say an integer, then none of the coercion procedures match. Because 's' is an expected parameter, that did not match the expected type, an error will be raised.

$p\left(\mathrm{expect}+\mathrm{an}+\mathrm{Error}\right);$