hold
-- delay evaluationhold(
object)
prevents the evaluation of
object
.
hold(object)
object |
- | any MuPAD object |
the unevaluated object.
Chapter 5 of the MuPAD Tutorial.
context
, delete
, eval
, freeze
, genident
, indexval
, level
, proc
, val
hold
is intended to prevent
such an evaluation when it is undesirable.hold
is when a function that
can only process numerical arguments, but not symbolical ones, is to be
plotted or to be subjected to some numerical algorithm. See
example 6.hold
is efficiency.
For example, if a function call f(x, y)
with symbolic
arguments is passed as argument to another function, but is known to
return itself symbolically, then the possibly costly evaluation of the
``inner'' function call can be avoided by passing the expression
hold(
f)
(x, y)
as argument to the
``outer'' function instead. Then the arguments x, y
are
evaluated, but the call to f
is not executed. See
examples 1 and 7.hold
may lead to strange effects, it is
recommended to use it only when absolutely necessary.hold
only delays the evaluation of an object, but
cannot completely prevent it on the long run; see example 5.
You can use freeze
to completely prevent the evaluation of a procedure or a function
environment.
hold
. This has the
effect that arguments are passed to the procedure unevaluatedly. See
the help page of proc
for
details.eval
or
level
can be used to
force a subsequent evaluation of an unevaluated object (see example 2). In procedures with option hold
, use context
instead.hold
is a function of the system kernel.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
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:
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
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
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:
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
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