## `eval` -- evaluate an object

#### Introduction

`eval(`object`)` evaluates its argument `object` by recursively replacing the identifiers occurring in it by their values and executing function calls, and then evaluates the result again.

#### Call(s)

`eval(object)`

#### Parameters

`object` | - | any MuPAD object

#### Returns

the evaluated object.

#### Side Effects

`eval` is sensitive to the value of the environment variable `LEVEL`, which determines the maximal substitution depth for identifiers.

#### Further Documentation

Chapter 5 of the MuPAD Tutorial.

#### Related Functions

`context`, `evalassign`, `evalp`, `freeze`, `hold`, `indexval`, `LEVEL`, `level`, `MAXLEVEL`, `MAXDEPTH`, `val`

#### Details

- `eval` serves to request the evaluation of unevaluated or partially evaluated objects. Evaluation means that identifiers are replaced by their values and function calls are executed.

  Usually, every system function automatically evaluates its arguments and returns a fully evaluated object, and using `eval` is only necessary in exceptional cases. For example, the functions `map`, `op`, and `subs` may return objects that are not fully evaluated. See example 1.

- Like most other MuPAD functions, `eval` first evaluates its argument. Then it evaluates the result again. At interactive level, the second evaluation usually has no effect, but this is different within procedures; see examples 3 and 4.
- `eval` is sensitive to the value of the environment variable `LEVEL`, which determines the maximal depth of the recursive process that replaces an identifier by its value during evaluation. The evaluation of the argument and the subsequent evaluation of the result both take place with substitution depth `LEVEL`. See example 3.

- If a local variable or a formal parameter, of type `DOM_VAR`, of a `procedure` occurs in `object`, then it is always replaced by its value when `eval` evaluates its argument, independent of the value of `LEVEL`. At the subsequent second evaluation, the value of the local variable is evaluated with substitution depth given by `LEVEL`, which usually is `1`. Cf. example 4.
- The behavior of `eval` within a procedure may sometimes not be what you expect, since the default substitution depth within procedures is `1` and `eval` evaluates with this substitution depth. Use `level` to request a complete evaluation within a procedure; see the corresponding help page for details.
- `eval` enforces the evaluation of expressions of the form `hold(x)`: `eval(`hold(x)`)` is equivalent to `x`. Cf. example 2.
- `eval` accepts expression sequences as arguments; see example 3. In particular, the call `eval(``)` returns the empty sequence `null()`.
- `eval` does not recursively descend into `arrays`. Use the call `map(object, eval)` to evaluate the entries of an array. Cf. example 5.

- `eval` does not recursively descend into `tables`. Use the call `map(object, eval)` to evaluate the entries of a table.

  However, it is not possible to evaluate the indices of a given table. If you want to do this, create a new table with the evaluated operands of the old one. Cf. example 6.

- `Polynomials` are not further evaluated by `eval`. Use `evalp` to substitute values for the indeterminates of a polynomial, and use the call `mapcoeffs(object, eval)` to evaluate all coefficients. Cf. example 7.
- The evaluation of elements of a user-defined `domain` depends on the implementation of the domain. Usually, domain elements remain unevaluated. If the domain has a slot `"evaluate"`, the corresponding slot routine is called with the domain element as argument at each evaluation, and hence it is called twice when `eval` is invoked. Cf. example 8.

- `eval` is a function of the system kernel.

#### Example 1

`subs` performs a substitution, but does not evaluate the result:

    >> subs(ln(x), x = 1)

                                       ln(1)

An explicit call of `eval` is necessary to evaluate the result:

    >> eval(subs(ln(x), x = 1))

                                         0

`text2expr` does not evaluate its result either:

    >> a := c:
       text2expr("a + a"), eval(text2expr("a + a"))

                                    a + a, 2 c

#### Example 2

The function `hold` prevents the evaluation of its argument. A later evaluation can be forced with `eval`:

    >> hold(1 + 1);  eval(%)

                                       1 + 1

                                         2

#### Example 3

When an object is evaluated, identifiers are replaced by their values recursively. The maximal recursion depth of this process is given by the environment variable `LEVEL`:

    >> delete a0, a1, a2, a3, a4:
       a0 := a1:  a1 := a2 + 2:  a2 := a3 + a4:  a3 := a4^2:  a4 := 5:

    >> LEVEL := 1:  a0, a0 + a2;
       LEVEL := 2:  a0, a0 + a2;
       LEVEL := 3:  a0, a0 + a2;
       LEVEL := 4:  a0, a0 + a2;
       LEVEL := 5:  a0, a0 + a2;

                                 a1, a1 + a3 + a4

                                              2
                               a2 + 2, a2 + a4  + 7

                             a3 + a4 + 2, a3 + a4 + 32

                                   2        2
                                 a4  + 7, a4  + 37

                                      32, 62

`eval` first evaluates its argument and then evaluates the result again. Both evaluations happen with substitution depth given by `LEVEL`:

    >> LEVEL := 1:  eval(a0, a0 + a2);
       LEVEL := 2:  eval(a0, a0 + a2);
       LEVEL := 3:  eval(a0, a0 + a2);

                                              2
                               a2 + 2, a2 + a4  + 7

                                   2        2
                                 a4  + 7, a4  + 37

                                      32, 62

Since the default value of `LEVEL` is `100`, `eval` usually has no effect at interactive level:

    >> delete LEVEL:
       a0, eval(a0), a0 + a2, eval(a0 + a2)

                                  32, 32, 62, 62

#### Example 4

This example shows the difference between the evaluation of identifiers and local variables. By default, the value of `LEVEL` is `1` within a procedure, i.e., a global identifier is replaced by its value when evaluated, but there is no further recursive evaluation. This changes when `LEVEL` is assigned a bigger value inside the procedure:

    >> delete a0, a1, a2, a3:
       a0 := a1 + a2:  a1 := a2 + a3:  a2 := a3^2 - 1:  a3 := 5:
       p := proc()
              save LEVEL;
            begin
              print(a0, eval(a0)):
              LEVEL := 2:
              print(a0, eval(a0)):
            end_proc:

    >> p()

                                                 2
                            a1 + a2, a2 + a3 + a3  - 1

                                           2
                               a2 + a3 + a3  - 1, 53

In contrast, evaluation of a local variable replaces it by its value, without further evaluation. When `eval` is applied to an object containing a local variable, then the effect is an evaluation of the value of the local variable with substitution depth `LEVEL`:

    >> q := proc()
              save LEVEL;
              local x;
            begin
              x := a0:
              print(x, eval(x)):
              LEVEL := 2:
              print(x, eval(x)):
            end_proc:
       q()

                                                 2
                            a1 + a2, a2 + a3 + a3  - 1

                                            2
                                 a1 + a2, a3  + 28

The command `x:=a0` assigns the value of the identifier `a0`, namely the unevaluated expression `a1+a2`, to the local variable `x`, and `x` is replaced by this value every time it is evaluated, independent of the value of `LEVEL`:

#### Example 5

In contrast to lists and sets, evaluation of an array does not evaluate its entries. Thus `eval` has no effect for arrays either. Use `map` to evaluate all entries of an array:

    >> delete a, b:
       L := [a, b]:  A := array(1..2, L):  a := 1:   b := 2:
       L, A, eval(A), map(A, eval)

                               +-    -+  +-    -+  +-    -+
                       [1, 2], | a, b |, | a, b |, | 1, 2 |
                               +-    -+  +-    -+  +-    -+

The call `map(A, gamma)` does not evaluate the entries of the array `A` before applying the function `gamma`. Map the function `gamma@eval` to enforce the evaluation:

    >> map(A, gamma), map(A, gamma@eval)

                         +-                  -+  +-    -+
                         | gamma(a), gamma(b) |, | 1, 1 |
                         +-                  -+  +-    -+

#### Example 6

Similarly, evaluation of a table does not evaluate its entries, and you can use `map` to achieve this. However, this does not affect the indices:

    >> delete a, b:
       T := table(a = b):  a := 1:  b := 2:
       T, eval(T), map(T, eval)

                            table(    table(    table(
                              a = b ,   a = b ,   a = 2
                            )         )         )

If you want a table with evaluated indices as well, create a new table from the evaluated operands of the old table. Using `eval` is necessary here since the operand function `op` does not evaluate the returned operands:

    >> op(T), table(eval(op(T)))

                                         table(
                                  a = b,   1 = 2
                                         )

#### Example 7

`Polynomials` are inert when evaluated, and also `eval` has no effect:

    >> delete a, x:  p := poly(a*x, [x]):  a := 2:  x := 3:
       p, eval(p), map(p, eval)

                  poly(a x, [x]), poly(a x, [x]), poly(a x, [x])

Use `mapcoeffs` to evaluate all coefficients:

    >> mapcoeffs(p, eval)

                                  poly(2 x, [x])

If you want to substitute a value for the indeterminate `x`, use `evalp`:

    >> delete x:  evalp(p, x = 3)

                                        3 a

As you can see, the result of an `evalp` call may contain unevaluated identifiers, and you can evaluate them by an application of `eval`:

    >> eval(evalp(p, x = 3))

                                         6

#### Example 8

The evaluation of an element of a user-defined `domains` depends on the implementation of the domain. Usually, it is not evaluated further:

    >> delete a:  T := newDomain("T"):
       e := new(T, a):  a := 1:
       e, eval(e), map(e, eval), val(e)

                    new(T, a), new(T, a), new(T, a), new(T, a)

If the slot `"evaluate"` exists, the corresponding slot routine is called for a domain element each time it is evaluated. We implement the routine `T::evaluate`, which simply evaluates all internal operands of its argument, for our domain `T`. The unevaluated domain element can still be accessed via `val`:

    >> T::evaluate := x -> new(T, eval(extop(x))):
       e, eval(e), map(e, eval), val(e)

                    new(T, 1), new(T, 1), new(T, 1), new(T, a)

#### Changes

- `eval` now works on all functions. Up to release 1.4.2, `eval` only evaluated the functions `args`, `coeff`, `evalp`, `expr`, `hold`, `input`, `last`, `lcoeff`, `nthcoeff`, `subs`, `subsex`, `subsop`, `tcoeff`, and `text2expr`.
- The evaluation of local variables and formal parameters (of the new data type `DOM_VAR`) in `eval` has changed. See sections "The LEVEL-Problem" and "Symbols and Variables" of the document "From MuPAD 1.4 to MuPAD 2.0" for details.

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