map
-- apply a function to all
operands of an objectmap(
object, f)
applies the function
f
to all operands of object
.
map(object, f <, p1, p2, ...>)
object |
- | an arbitrary MuPAD object |
f |
- | a function |
p1, p2, ... |
- | any MuPAD objects accepted by f as
additional parameters |
a copy of object
with f
applied to all
operands.
object
eval
, mapcoeffs
, misc::maprec
, op
, select
, split
, subs
, subsex
, subsop
, zip
map(
object, f)
returns a copy of
object
where each operand
x
has been replaced by f(x)
. The object
itself is not modified by map
(see example 2).f
may be a procedure generated via ->
or
proc
(e.g., x ->
x^2 + 1
), a function environment
(e.g., sin
), or a
functional expression (e.g., sin@exp + 2*id
).x
of object
is replaced
by f(x, p1, p2, ...)
(see example 1).+
or *
, to all operands of object
,
by using its functional equivalent, such as _plus
or _mult
. See example 1.op
,
map
does not decompose rational numbers and complex
numbers further. Thus, if the argument is a rational number or a complex number, then f
is applied to
the number itself and not to the numerator and the denominator or the
real part and the imaginary part, respectively (see example 3).object
is a string,
then f
is applied to the string as a whole and not to the
individual characters (see example 3).object
is an expression,
then f
is applied to the operands of f
as
returned by op
(see example
1).object
is an expression
sequence, then this sequence is not flattened by map
(see example 4).object
is a polynomial,
then f
is applied to the polynomial itself and not to all
of its coefficients. Use mapcoeffs
to achieve the latter
(see example 3).object
is a list, a set, or an array,
then the function f
is applied to all elements of the
corresponding data structure.If object
is a table, the function f
is applied to
all entries of the table, not to the indices (see example 9). The entries are the right sides of the operands of a table.
object
is an element of a library domain, then the slot "
map" of the
domain is called and the result is returned. This can be used to extend
the functionality of map
to user-defined domains. If no
"
map" slot exists, then f
is applied to the
object itself (see example 10).map
does not evaluate its result after the
replacement; use eval
to
achieve this. Nevertheless, internal simplifications occur after the
replacement (see example 8).map
does not descend recursively into an object; the
function f
is only applied to the operands at first level.
Use misc::maprec
for a
recursive version of map
(see example 11).map
is a function of the system kernel.map
works for expressions:
>> map(a + b + 3, sin)
sin(a) + sin(b) + sin(3)
The optional arguments of map
are passed to
the function being mapped:
>> map(a + b + 3, f, x, y)
f(a, x, y) + f(b, x, y) + f(3, x, y)
In the following example, we add 10
to each
element of a list:
>> map([1, x, 2, y, 3, z], _plus, 10)
[11, x + 10, 12, y + 10, 13, z + 10]
Like most other MuPAD functions, map
does not modify its first argument, but returns a modified copy:
>> a := [0, PI/2, PI, 3*PI/2]: map(a, sin)
[0, 1, 0, -1]
The list a
still has its original
value:
>> a
-- PI 3 PI -- | 0, --, PI, ---- | -- 2 2 --
map
does not decompose rational and complex
numbers:
>> map(3/4, _plus, 1), map(3 + 4*I, _plus, 1)
7/4, 4 + 4 I
map
does not decompose strings:
>> map("MuPAD", text2expr)
MuPAD
map
does not decompose polynomials:
>> map(poly(x^2 + x + 1), _plus, 1)
2 poly(x + x + 1, [x]) + 1
Use mapcoeffs
to apply a function to
all coefficients of a polynomial:
>> mapcoeffs(poly(x^2 + x + 1), _plus, 1)
2 poly(2 x + 2 x + 2, [x])
The first argument is not flattened:
>> map((1, 2, 3), _plus, 2)
3, 4, 5
Sometimes a MuPAD function returns a set or a
list of big symbolic expressions containing mathematical constants etc.
To get a better intuition about the result, you can map the function
float
to all elements,
which often drastically reduces the size of the expressions:
>> solve(x^4 + x^2 + PI, x)
{ 1/2 1/2 1/2 1/2 1/2 1/2 { 2 ((1 - 4 PI) - 1) 2 ((1 - 4 PI) - 1) { - ---------------------------, ---------------------------, { 2 2 1/2 1/2 1/2 2 (- (1 - 4 PI) - 1) - -----------------------------, 2 1/2 1/2 1/2 } 2 (- (1 - 4 PI) - 1) } ----------------------------- } 2 }
>> map(%, float)
{- 0.7976383425 - 1.065939457 I, - 0.7976383425 + 1.065939457 I, 0.7976383425 - 1.065939457 I, 0.7976383425 + 1.065939457 I}
In the following example, we delete the values of all
global identifiers in the current MuPAD session. The command
anames(All, User)
returns a set with the names of all user-defined global identifiers
having a value. Mapping the function _delete
to this set deletes the
values of all these identifiers. Since the return value of _delete
is the empty sequence
null()
, the result of the
call is the empty set:
>> x := 3: y := 5: x + y
8
>> map(anames(All, User), _delete)
{}
>> x + y
x + y
It is possible to perform arbitrary actions with all
elements of a data structure via a single map
call. This
works by passing an anonymous procedure as
the second argument f
. In the following example, we check
that the fact ``an integer n >= 2 is prime if and only if
phi(n) = n - 1'', where phi denotes Euler's
totient function, holds for all integer 2 <= n < 10.
We do this by comparing the result of isprime(n)
with the truth value of
the equation phi(n) = n - 1 for all elements n
of a list containing the integers between 2
and
9
:
>> map([2, 3, 4, 5, 6, 7, 8, 9], n -> bool(isprime(n) = bool(numlib::phi(n) = n - 1)))
[TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE]
The result of map
is not evaluated further.
If desired, you must request evaluation explicitly by eval
:
>> map(sin(5), float); eval(%)
sin(5.0) -0.9589242747
Nevertheless, certain internal simplifications take
place, such as the calculation of arithmetical operations with
numerical arguments. The following call replaces sqrt(2)
and PI
by floating point approximations, and the system
automatically simplifies the resulting sum:
>> map(sin(5) + cos(5), float)
-0.6752620892
map
applied to a table changes only the right sides (the entries) of
each operand of the table. Assume the entries
stand for net prices and the sales tax (16 percent in this case) must
be added:
>> T := table(1 = 65, 2 = 28, 3 = 42): map(T, _mult, 1.16)
table( 3 = 48.72, 2 = 32.48, 1 = 75.4 )
map
can be overloaded for elements of library domains, if a slot "
map" is defined. In this example
d
is a domain, its elements contains two integer numbers:
an index and an entry (like a table). For nice input and printing
elements of this domain the slots
"new"
and "print"
are defined:
>> d := newDomain("d"): d::new := () -> new(d, args()): d::print := object -> _equal(extop(object)): d(1, 65), d(2, 28), d(3, 42)
1 = 65, 2 = 28, 3 = 42
Without a slot "
map" the function
f
will be applied to the domain element itself. Because
the domain d
has no slot "
_mult", the result is the symbolic _mult
call:
>> map(d(1, 65), _mult, 1.16), type(map(d(1, 65), _mult, 1.16))
1.16 (1 = 65), "_mult"
The slot "
map" of this domain should map
the given function only onto the second operand of a domain element.
The domain d
gets a slot "
map" and
map
works properly (in the authors sense) with elements of
this domain:
>> d::map := proc(obj, f) begin if args(0) > 2 then d(extop(obj, 1), f(extop(obj, 2), args(3..args(0)))) else d(extop(obj, 1), f(extop(obj, 2))) end_if end_proc: map(d(1, 65), _mult, 1.16), map(d(2, 28), _mult, 1.16), map(d(3, 42), _mult, 1.16)
1 = 75.4, 2 = 32.48, 3 = 48.72
map
does not work recursively. Suppose that
we want to de-nest a nested list. We use map
to apply the
function op
, which replaces
a list by the sequence of its operands, to all entries of the list
l
. However, this only affects the entries at the first
level:
>> l := [1, [2, [3]], [4, [5]]]: map(l, op)
[1, 2, [3], 4, [5]]
Use misc::maprec
to achieve the desired
behavior:
>> [misc::maprec(l, {DOM_LIST} = op)]
[1, 2, 3, 4, 5]