Previous Page Next Page Contents

hold -- delay evaluation

Introduction

hold(object) prevents the evaluation of object.

Call(s)

hold(object)

Parameters

object - any MuPAD object

Returns

the unevaluated object.

Further Documentation

Chapter 5 of the MuPAD Tutorial.

Related Functions

context, delete, eval, freeze, genident, indexval, level, proc, val

Details

Example 1

In the following two examples, the evaluation of a MuPAD expression is prevented using hold:

>> x := 2:
   hold(3*0 - 1 + 2^2 + x)
                                        2
                             3 0 - 1 + 2  + x
>> hold(error("not really an error"))
                       error("not really an error")

Without hold, the results would be as follows:

>> x := 2:
   3*0 - 1 + 2^2 + x
                                     5
>> error("not really an error")
      Error: not really an error

The following command prevents the evaluation of the operation _plus, but not the evaluation of the operands:

>> hold(_plus)(3*0, -1, 2^2, x)
                               0 - 1 + 4 + 2

Note that in the preceding example, the arguments of the function call are evaluated, because hold is applied only to the function _plus. In the following example, the argument of the function call is evaluated, despite that fact that f has the option hold:

>> f := proc(a)
          option hold;
        begin
          return(a + 1)
        end_proc:
   x := 2:
   hold(f)(x)
                                   f(2)

This happens for the following reason. When f is evaluated, the option hold prevents the evaluation of the argument x of f (see the next example). However, if the evaluation of f is prevented by hold, then the option hold has no effect, and MuPAD evaluates the operands, but not the function call.

The following example shows the expected behavior:

>> f(x), hold(f(x))
                                x + 1, f(x)

The function eval undoes the effect of hold. Note that it yields quite different results, depending on how it is applied:

>> eval(f(x)), eval(hold(f)(x)), eval(hold(f(x))), eval(hold(f))(x)
                            3, 3, x + 1, x + 1

Example 2

Several hold calls can be nested to prevent subsequent evaluations:

>> x := 2:
   hold(x), hold(hold(x))
                                x, hold(x)

The result of hold(hold(x)) is the unevaluated operand of the outer call of hold, that is, hold(x). Applying eval evaluates the result hold(x) and yields the unevaluated identifier x:

>> eval(%)
                                   2, x

Another application of eval yields the value of x:

>> eval(%)
                                   2, 2
>> delete x, f:

Example 3

The following command prevents the evaluation of the operation _plus, replaces it by the operation _mult, and then evaluates the result:

>> eval(subsop(hold(_plus)(2, 3), 0 = _mult))
                                     6

Example 4

The function domtype evaluates its arguments:

>> x := 0:
   domtype(x), domtype(sin), domtype(x + 2)
                      DOM_INT, DOM_FUNC_ENV, DOM_INT

Using hold, the domain type of the unevaluated objects can be determined: x and sin are identifiers, and x + 2 is an expression:

>> domtype(hold(x)), domtype(hold(sin)), domtype(hold(x + 2))
                      DOM_IDENT, DOM_IDENT, DOM_EXPR

Example 5

hold prevents only one evaluation of an object, but it does not prevent evaluation at a later time. Thus using hold to obtain a a symbol without a value is usually not a good idea:

>> x := 2:
   y := hold(x);
   y
                                     x
      
                                     2

In this example, deleting the value of the identifier x makes it a symbol, and using hold is not necessary:

>> delete x:
   y := x;
   y
                                     x
      
                                     x

However, the best way to obtain a new symbol without a value is to use genident:

>> y := genident("x");
   y
                                    x1
      
                                    x1
>> delete y:

Example 6

Suppose that we want to plot the graph of the piecewise continuous function f(x) that is identically zero on the negative real axis and equal to exp(-x) on the positive real axis:

>> f := x -> if x < 0 then 0 else exp(-x) end_if:

If we pass the symbolical expression f(x) as an argument to plotfunc2d, then an error occurs:

>> delete x:
   plotfunc(f(x), x = -2..2)
      Error: Can't evaluate to boolean [_less];
      during evaluation of 'f'

The reason is that plotfunc2d evaluates its arguments, and the evaluation of f(x) for a symbolical argument x leads to an error:

>> f(x)
      Error: Can't evaluate to boolean [_less];
      during evaluation of 'f'

A solution is to use hold:

>> plotfunc2d(hold(f)(x), x = -2..2):

The same phenomenon occurs when we want to apply numerical integration to f:

>> numeric::int(f(x), x = -2..2)
      Error: Can't evaluate to boolean [_less];
      during evaluation of 'f'
>> numeric::int(hold(f)(x), x = -2..2)
                               0.8646647168

Example 7

The function int is unable to compute a closed form of the following integral and returns a symbolic int call:

>> int(sin(x)*sqrt(sin(x) + 1), x)
                                             1/2
                      int(sin(x) (sin(x) + 1)   , x)

After the change of variables sin(x)=t, a closed form can be computed:

>> t := time():
   f := intlib::changevar(int(sin(x)*sqrt(sin(x) + 1), x), sin(x) = y);
   time() - t;
   eval(f)
                             /          1/2    \
                             | y (y + 1)       |
                          int| ------------, y |
                             |       2 1/2     |
                             \ (1 - y )        /
      
                                   9210
      
                                    1/2 / 2 y       \
                     (y - 1) (y + 1)    | --- + 4/3 |
                                        \  3        /
                     --------------------------------
                                     2 1/2
                               (1 - y )

Measuring computing times with time shows: Most of the time in the call to intlib::changevar is spent in re-evaluating the argument. This can be prevented by using hold:

>> t := time():
   f := intlib::changevar(hold(int)(sin(x)*sqrt(sin(x) + 1), x),
                          sin(x) = y);
   time() - t;
                             /          1/2    \
                             | y (y + 1)       |
                          int| ------------, y |
                             |       2 1/2     |
                             \ (1 - y )        /
      
                                    20

Changes




Do you have questions or comments?


Copyright © SciFace Software GmbH & Co. KG 2000