## `map` -- apply a function to all operands of an object

#### Introduction

`map(`object, f`)` applies the function `f` to all operands of `object`.

#### Call(s)

`map(object, f <, p1, p2, ...>)`

#### Parameters

`object` | - | an arbitrary MuPAD object
`f` | - | a function
`p1, p2, ...` | - | any MuPAD objects accepted by `f` as additional parameters

#### Returns

a copy of `object` with `f` applied to all operands.

### Overloadable:

`object`

#### Related Functions

`eval`, `mapcoeffs`, `misc::maprec`, `op`, `select`, `split`, `subs`, `subsex`, `subsop`, `zip`

#### Details

- `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).

- The second argument `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`).
- If optional arguments are present, then each operand `x` of `object` is replaced by `f(x, p1, p2, ...)` (see example 1).

- It is possible to apply an operator, such as `+` or `*`, to all operands of `object`, by using its functional equivalent, such as `_plus` or `_mult`. See example 1.

- In contrast to `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).

- If `object` is a string, then `f` is applied to the string as a whole and not to the individual characters (see example 3).

- If `object` is an expression, then `f` is applied to the operands of `f` as returned by `op` (see example 1).

- If `object` is an expression sequence, then this sequence is not flattened by `map` (see example 4).

- If `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).

- If `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.

- If `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.

#### Example 1

`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]

#### Example 2

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   --

#### Example 3

`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])

#### Example 4

The first argument is not flattened:

    >> map((1, 2, 3), _plus, 2)

                                      3, 4, 5

#### Example 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}

#### Example 6

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

#### Example 7

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]

#### Example 8

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

#### Example 9

`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
                                   )

#### Example 10

`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

#### Example 11

`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]

#### Changes

- no changes

Do you have questions or comments?
Copyright © SciFace Software GmbH & Co. KG 2000