Callable

new to Analytica 7.0

Callable class

A Callable Object is a Variable subclass. Like a Variable, it has a mid-value and a sample-value that are computed by evaluating its Definition.

The result of a Callable is expected to be a value that is itself callable with parameters. For example, its value might be a Local function, a handle to an Analytica function, a python function, a python class, or even an array of these.

In other words, the Callable instance is a type of Variable, but its value is a function-like instance.

Comparison to a Variable class

The Callable class provides two advantages over a Variable class. First, it displays with a function-like shape on an influence diagram, which may better reflect the logical purpose of the node, and second, it allows you to use a X(a,b,c) syntax to call it instead of the X->(a,b,c) syntax that would be required with a normal Variable. This is most useful when intermixing Python code. For example, when a Callable object's definition is set to be a Python expression that contains a function def or a class declaration.

A callable behaves as if it were a type of Variable. It has a definition, which gets evaluated when the callable itself is evaluated. It caches its computed value, and it contains dependencies to and from other variables. The primary distinction is that a Variable is generally used when you expect the result to be a final (non-callable) value, whereas the result for the Callable is expected to be a callable value. But neither is a hard requirement.

If you define a Variable, X, such that its computed result is a function, you could call that function using the syntax:

X->(a,b,c)

The arrow operator performs the operation at the atomic cell level (whereas the dot operator, e.g., A.I, is an array-level operation). You can also use this arrow syntax when using a Callable, but because it is a callable you can also use the more natural calling syntax,

X(a,b,c)


Comparison to a Function class

Unlike a Function node, which is a single fixed-function, the specific function (or array of functions) is computed when the Callable itself is evaluated. Thus, a callable can be used to select which underlying function to use based on other computed criteria, or can actually define the function on the fly (when the Callable itself is evaluated).

Using with Python functions

( Use of Python requires the Analytica Developer edition or better)

A Callable is a natural class to use for a Python function. Select Python Expression from the Definition-type pulldown. For an existing python function in a library, you can set the Definition (python expression) to, e.g.,

from scipy.signal import bilinear

For a function already in the global python namespace, you can set the Definition (python expression) to its name, or use the python dot notation (Python's equivalent to Analyticas -> operator) to extract a function from a library or class that is in scope.

From an Analytica expression view, you can set the Definition to

py::fn

or

py::someModule->fn

When you wish to define a Python function inside your model, the Callable is the natural place to do this. In this case, select Python expression from the Definition-type pulldown, and enter the python "def", e.g.,

(insert object window screenshot here with a def)

Using with Python classes

Using with global Analytica functions

Using a callable as an intermediary to a given global function would be inferior in several ways to simply calling the function directly. A potential use case that could make sense would be if you had many global functions with the same parameters, and you want to include logic to select the function without necessarily calling it yet with parameter values. In this case, the Definition of the Callable could compute which function (or functions) should be used.

This might occur in a UI Choice or MultiChoice where you allow your user to select between functions (each option is a Handle to a function). Alternatively, a DetermTable of function handles may be convenient. Or perhaps you have more complex logic involving arbitrary calculations.

Once you've determined the function, the shape of the Callable for the selected function(s) reflects the logical function, and the call to the underlying function looks like a normal function call. This might be compared to the alternative of using an explicit call to Evaluate, passing the function handle as the first parameter.

Using with local functions (lambdas)

Here is an example use case where the result of evaluating the Definition results in a Local function. In this example, we want a generator, Count(), that returns an integer but increments the value each time we call it. This could, for example, be used to assign a unique ID to new records.

Callable Count ::=

Local i:=0;
Function getCount( a : optional ... atom ) : ( i := i + 1 ) Do getCount

Now from elsewhere in your model, you can use Count() to get the next integer. You can also use

Count( Record )

to get an array of incremented integers over the Record index, or

Count( I, J, K)

to get an array over the I, J and K indexes.

If you instead used a Variable instead of a Callable, the syntax would be:

Count->( )
Count->( Record )
Count->( I, J, K )

which is less convenient (but also works even with the Callable).

See also

Comments


You are not allowed to post comments.