Evaluate


Evaluate(t)

Evaluate is a powerful, but rarely needed function. If the parameter «t» is a text value, Evaluate expects «t», tries to evaluate it as though it were an expression in a definition, and returns the resulting value. For example:

Evaluate('10 * 10') → 100

If «t» is a Handle to a variable, Evaluate evaluates the variable and returns its value:

Variable A := 100
Evaluate(Handle(A)) → 100

You can also use it to evaluate a function passed as an object or handle:

Function Add(a, b)  := a*b
Evaluate(Handle(Add), 2, 10) → 20

This can be useful when you want to define a function that takes a function as a parameter and applies the function in its body. See #Using Evaluate on a Function below.

Evaluate a text value

There are several subtleties and limitations to Evaluate(). You should use it with care.

If text «t» contains a syntax error, Evaluate(«t») gives no error message, and returns Null.

The context inside the Evaluate parameter is global, not local. Thus:

Variable A := 100
Variable B := (VAR A := 0; Evaluate('A + 1'))
B & rarr; 101

The Variable A inside Evaluate('A + 1') refers to the global A, not the local A defined in B. More generally:

  • Evaluate(t) creates its own context for parsing «t» (at evaluation time), quite different from the context of the expression in which the Evaluate(t) appears -- e.g., the definition of B above.
  • Thus, text «t» cannot refer to local values, indexes, or function parameters defined in the context in which the Evaluate(t) function appears.
  • Text «t» may itself define local values and indexes, and refer to them, but these will not be available outside «t».
  • If the text value of «t» refers to a global variable —e.g., A in the definition of B above—these do not appear as Inputs of B.
  • Analytica will not be able to track the dependency of any variable name that appears inside the text. So, any changes to A will not cause automatic re-evaluation of B. For example:
B := A + 1
C := Evaluate('A + 1')

When A changes, Analytica will automatically ensure that B is updated, but it has no way of knowing C should also be recomputed.

Text «t» may itself be an expression that creates a text value to be evaluated by Evaluate. This text expression appears in the definition of V and is not subject to the above limitations, so, for example:

Variable V :=(Var x:= ’10’; Evaluate(x & x))
V → 1010

When to Use

The cases in which you should use Evaluate are rare. You should be reluctant to use it due to the caveats listed in the previous section. Typical cases when it is useful include:

  • Parsing numbers or simple expressions.
  • (advanced) Use in Meta-Inference algorithms where you are manipulating handles to objects in your model.
  • (rare) Cases where you really do wish to by-pass dependency maintenance. You want it to compute something the first time the result is requested after the model is first loaded, but not update when parent values are changes.

Non-text Parameters

A non-text value can also be passed to Evaluate, which can be of use in some Meta-Inference applications. You need to keep in mind that the parameter to evaluate is evaluated BEFORE the function itself gets it, so evaluating a non-text value is only meaningful when the evaluated parameter is itself something that can still be evaluated. One instance of this that is often useful is the case of a handle an object.

For example, suppose

Variable A := 2 + 3
Variable TheVar := Handle(A)

In the more general case, you might have a Meta-Inference algorithm that identifies a single variable object through some computation. Having identified the object, TheVar now holds a handle to the object. You then may want to access values or properties of the object pointed to by TheVar, rather than just values or properties of TheVar itself. Evaluate serves this purpose:

TheVar → A { A -- i.e., a handle to the object A }
Evaluate(TheVar) → 5 { evaluates A }

It is worth nothing that an alternative method also exists for evaluating a handle. You can declare a LocalAlias set to the handle, and then use its identifier as if it were the identifier of the object.

LocalAlias x := TheVar Do x → 5 { x is an alias for A, so "x" in the body is the value of A }

When accessing attributes of an object in a Meta-Inference algorithm, where your algorithm has a handle to an object (again, say it is in TheVar), you can access the attribute using e.g.,

Description Of Evaluate(TheVar) → "Description of A"
Description Of TheVar → "Description of TheVar"

(the result of using TheVar alone is shown for comparison).

Using Evaluate on a Function

Given a handle to a function object, you can use Evaluate to call the function. If the function expects N parameters, you would provide N+1 parameters to Evaluate -- the first parameter being the handle to the function, and the remaining parameters being the values passed to the function. Example:

MetaVar fn := If opt = 1 then Handle(Max) else if opt = 2 then Handle(Min) else Handle(Sum);
Evaluate(fn, A, I)

Parameters to the function being called are always passed by position, i.e., you cannot use a named-parameter calling syntax as you might if you were calling the function directly.

If the function being called contains repeated (or variable number of) parameters, and you need to include a parameter that follows the repeated parameter, then you must place brackets around the repeated parameters. For example,

Function Fu1(x; y: repeated; z: optional) := ...
 
Evaluate(fn, 1, 2, 3, 4) →
Equivalent to Fu1(1, 2, 3, 4), where [2, 3, 4] are values for y and z is omitted
Evaluate(fn, 1, [2, 3], 4) →
Equivalent to Fu1(1, 2, 3, y: 4), where [2, 3] are values for y, and z is 4.

However, there is a limitation that the first supplied parameter (i.e., the second parameter to Evaluate) cannot be placed inside brackets. Likewise, you cannot pass an literal list by specifying the first parameter as a bracketed list. This is because the repeated-parameter syntax applies equally to Evaluate. If you specify the first parameter to Evaluate in brackets, those become the parameters to the function, i.e.,:

Evaluate(Handle(F), [1, 2, 3, 4]) →
Equivalent to F(1, 2, 3, 4)

Several common built-in functions, including Sum, Max, and Min, allow a variable number of indexes, so that you can use Sum(A, I, J, K) to sum over 3 dimensions in a single call. These functions also have optional parameters, such as «ignoreNonNumbers», so that if you need to specify these optional parameters, you will need to place brackets around the index(es), even if only one (or zero) index is specified. For example, the following examples show how to to specify «ignoreNonNumbers» as true to Sum, when summing over a single index, and when summing over the implicit dimension:

Evaluate(Handle(Sum), A, [I], true)
Var x := [3, 2, 'a', 'b', 6] do Evaluate(Handle(Sum), x, [], true)

Notice that if you don't need to specify the optional «ignoreNonNumbers» parameter (or any parameters that follow the repeated index parameters), then it is more natural to omit the brackets:

Evaluate(Handle(Sum), A, I)
Var x := [3, 2, 5, 3, 6] do Evaluate(Handle(Sum), x)

See Also

Comments


You are not allowed to post comments.