Difference between revisions of "Parameter qualifiers"

(28 intermediate revisions by 3 users not shown)
Line 2: Line 2:
 
[[Category: Functions]]
 
[[Category: Functions]]
  
<breadcrumbs>Analytica User Guide > Building Functions and Libraries > {{PAGENAME}}</breadcrumbs><br />
+
<breadcrumbs>Analytica User Guide > User-defined Functions and Libraries > {{PAGENAME}}</breadcrumbs><br />
  
 +
Parameter qualifiers are keywords used in the Parameters attribute of a function to specify what kind of value the function expects for each parameter. They include:
 +
*'''Class Qualifiers''', such as '''Index''' and '''Variable''', which specify what class of Object is expected.
 +
*'''Evaluation mode qualifiers''', such as '''Mid''' and '''Prob''', control whether to evaluate a parameter as deterministic or probabilistic.
 +
*'''Data type qualifiers''', such as '''Number''', '''Text''', '''Reference''', and '''Handle''', which specify the expected data type.
 +
*'''Dimension qualifiers''', such as '''Atom''', '''List''', '''Array''', and '''[i]''', which specify the expected array dimensions and support array abstraction.
 +
* '''Optional''' and '''Repeated''' (or ...) specify whether a parameter is optional (with default value) or may be repeated.
 +
 +
<div style="column-count:3;-moz-column-count:3;-webkit-column-count:3">
 
__TOC__
 
__TOC__
 +
</div>
  
Parameter qualifiers are keywords you can use in the list of parameters to specify how, or whether, each parameter should be evaluated when the function is used (called), and whether to require a particular type of value, such as number or text value. Other qualifiers specify whether a parameter should be an array, and if so, which indexes it expects. You can also specify whether a parameter is optional, or can be repeated. By using qualifiers properly, you can help make functions easier to use, more flexible, and more reliable.
+
== Introducing parameter qualifiers ==
  
For example, consider this parameters attribute:
+
Parameter qualifiers help make sure that each parameter gets the kind of value or object that the function expects. They help detect or avoid errors when using [[Functions by category|System functions]] and [[User-defined functions]]. If the actual parameter is different from what the qualifier specifies, Analytica may be able to convert it to what was expected, or otherwise flags an error.
  
:<code>(a: Number Array[i, j]; i, j: Index; c; d: Atom Text Optional = “NA”)</code>
+
For example, this function returns the value of index i for which array tList indexed by i contains text matching t:
  
It defines five parameters. <code>a</code> should be an array of numbers, indexed by parameters <code>i</code> and <code>j</code>, and optionally other indexes. <code>i</code> and <code>j</code> must be index variables. <code>c</code> has no qualifiers, and so can be of any type or dimensions. (The semicolon “;” between <code>c</code> and <code>d</code> means that the qualifiers following <code>d</code> do  not apply to <code>c</code>. <code>d</code> is an '''Atom Text''', meaning that it is reduced to a single text value each time the function is called, and is optional. If omitted it defaults to “<code>NA</code>”. See below for details.
+
:Function <code>TextMatch</code>(t, tList, i, caseSensitive )
 +
:'''Parameters:''' <code>(t: Text Atom; tList: Text [i]; i: Index; caseSensitive: Boolean Atom Optional = True)</code>
 +
:'''Description:''' If t matches a cell in tlist, a vector of text values indexed by i, it returns the value of i, otherwise Null.</code>
 +
::By default the match is sensitive to letter case. If you specify optional parameter caseSensitive as False, it ignores the letter cases.  
 +
:'''Definition: '''
 +
::<code>[[If]] [[Not]] caseSensitive [[Then]] (</code>
 +
:::<code> t := [[TextUpperCase]](t); </code>
 +
:::<code> tList := [[TextUpperCase]](tList) </code>
 +
::<code>);</code>
 +
::<code>[[SubIndex]]( tList, t, i)</code>
  
==What you must know==
+
In the [[Parameters]] attribute, each parameter is followed by ":" and one or more qualifiers.
 +
The qualifier '''Text''' specifies that '''t''' and '''tList''' must contain [[Text]] values (not numbers).
 +
The dimension qualifiers '''[i]''' and '''Index''' specify that '''tList''' should have an index ''i'', and parameter '''i''' should be the identifier of that Index.  It will give an error message if '''i''' is not an Index variable.  The qualifiers '''Boolean Optional = True''' specify that parameter '''caseSensitive''' should be a [[Boolean]] (True or False) and is optional. If omitted, it defaults to True -- i.e. the text match is sensitive to whether letters are upper- or lowercase.
  
If you learn about no other qualifiers, the one qualifier you need to know about is [[Function_parameter_qualifiers#Index|Index]]. You should think about it this way: some parameters are values, and some parameters are indexes. The value parameters can exist with no qualifiers, but an index parameter must have the [[Function_parameter_qualifiers#Index|Index]] qualifier. If you create a function that operates over an index, you’ll want an index qualifier.
+
If you write your own  [[User-defined functions]], it is important to understand at least the basics of parameter qualifiers. If not, you may find it useful when you are using built-in functions.
  
As an example, consider a function to return the last slice of an array along a given index.
+
==What you must know==
  
:<code>Function Last(x; I: Index)</code>
+
If you learn about no other qualifiers, the one qualifier you need to know about is [[Parameter_qualifiers#Index|Index]]. You should think about it this way: some parameters are values, and some parameters are indexes. The value parameters can exist with no qualifiers, but an index parameter must have the [[Function_parameter_qualifiers#Index|Index]] qualifier. If you create a function that operates over an index, you’ll want an index qualifier.
:<code>Definition: Slice(x, I, Size(I))</code>
 
  
Because <code>x</code> and <code>I</code> are separated by a semicolon, the [[Function_parameter_qualifiers#Index|Index]] qualifier applies only to <code>I</code>. When you call this function, you must supply an index for the second parameter.
 
  
 
==Evaluation mode qualifiers==
 
==Evaluation mode qualifiers==
  
 
Evaluation modes control how, or whether, Analytica evaluates each parameter when a function is used (called). The evaluation mode qualifiers are:
 
Evaluation modes control how, or whether, Analytica evaluates each parameter when a function is used (called). The evaluation mode qualifiers are:
 +
 +
===Mid===
 +
 +
[[Function_parameter_qualifiers#Mid|Mid]] evaluates the parameter determinstically, or in [[mid]] mode, using the mid (usually [[median]]) of any explicit probability distribution.
 +
 +
===Prob===
 +
 +
[[Function_parameter_qualifiers#Prob|Prob]] evaluates the parameter probabilistically, i.e., in prob mode, if it can. If you declare the dimension of the parameter, include the dimension [[Run]] in the declaration if you want the variable to hold the full sample, or omit [[Run]] from the list if you want the variable to hold individual samples. For example:
 +
 +
:<code>(A: Prob [In1, Run])</code>
 +
 +
===Sample===
 +
 +
[[Function_parameter_qualifiers#Sample|Sample]] evaluates the parameter probabilistically, i.e., in prob mode, if it can. If you declare the dimension of the parameter, include the dimension [[Run]] in the declaration if you want the variable to hold the full sample, or omit [[Run]] from the list if you want the variable to hold individual samples. For example:
 +
 +
:<code>(A: Sample[In1, Run])</code>
  
 
===Context===
 
===Context===
  
Evaluates the parameter deterministically or probabilistically according to the current context. For example:
+
[[Function_parameter_qualifiers#Context|Context]] evaluates the parameter deterministically or probabilistically according to the current context. For example:
  
 
:<code>Function Fn1(x)</code>
 
:<code>Function Fn1(x)</code>
 
:<code>Parameters: (x: Context)</code>
 
:<code>Parameters: (x: Context)</code>
:<code>Mean(Fn1(x))</code>
+
:<code>[[Mean]](Fn1(x))</code>
  
 
[[Mean]]() is a statistical function that always evaluates its parameter probabilistically. Hence, the evaluation context for <code>x</code> is probabilistic, and so <code>Fn1</code> evaluates <code>x</code> probabilistically.  
 
[[Mean]]() is a statistical function that always evaluates its parameter probabilistically. Hence, the evaluation context for <code>x</code> is probabilistic, and so <code>Fn1</code> evaluates <code>x</code> probabilistically.  
Line 49: Line 83:
 
:<code>Mean(x: ContextSample[i]; i: Index = Run)</code>
 
:<code>Mean(x: ContextSample[i]; i: Index = Run)</code>
  
Thus, <code>Mean(x, Run)</code> evaluates <code>x</code> in prob mode. So does <code>Mean](x)</code>, because the index <code>i</code> defaults to [[Run]]. But, <code>Mean(x, j)</code> evaluates <code>x</code> in [[mid]] mode, because <code>j</code> is not [[Run]].
+
Thus, <code>[[Mean]](x, [[Run]])</code> evaluates <code>x</code> in prob mode. So does <code>[[Mean]](x)</code>, because the index <code>i</code> defaults to [[Run]]. But, <code>[[Mean]](x, j)</code> evaluates <code>x</code> in [[mid]] mode, because <code>j</code> is not [[Run]].
  
 
When the parameter declaration contains more than one dimension, prob mode is used if any of the indexes is [[Run]].
 
When the parameter declaration contains more than one dimension, prob mode is used if any of the indexes is [[Run]].
  
===Mid===
 
  
[[Function_parameter_qualifiers#Mid|Mid]] evaluates the parameter determinstically, or in [[mid]] mode, using the mid (usually [[median]]) of any explicit probability distribution.
 
  
===Prob===
+
===Index===
  
[[Function_parameter_qualifiers#Prob|Prob]] evaluates the parameter probabilistically, i.e., in prob mode, if it can. If you declare the dimension of the parameter, include the dimension [[Run]] in the declaration if you want the variable to hold the full sample, or omit [[Run]] from the list if you want the variable to hold individual samples. For example:
+
[[Function_parameter_qualifiers#Index|Index]] indicates that the parameter must be an index variable, or a [[dot-operator]] expression, such as <code>a.i</code>. You can then use the parameter as a local index within the function definition. This is useful if you want to use the index in a function that requires an index, for example <code>[[Sum]](x, i)</code> within the function.
  
:<code>(A: Prob [In1, Run])</code>
+
===Variable===
  
===Sample===
+
[[Function_parameter_qualifiers#Variable|Variable]] or <code>Var</code> indicates that the parameter must be a variable, i.e., and unquoted identifier of a variable object. You can then treat the parameter name as equivalent to the variable within the function definition. Here the parameter name is a [[LocalAlias|local alias]] of the variable, and the variable does not get evaluated by the function call, which is different from a <code>[[Function_parameter_qualifiers#Context|Context]]</code> where the parameter is evaluated and the resulting ''value'' is passed in. <code>Variable</code> is useful if you want to use the variable in one of the few expressions or built-in functions that require a variable as a parameter, for example, [[WhatIf]], [[Dydx]], and [[Elasticity]].
  
[[Function_parameter_qualifiers#Sample|Sample]] evaluates the parameter probabilistically, i.e., in prob mode, if it can. If you declare the dimension of the parameter, include the dimension [[Run]] in the declaration if you want the variable to hold the full sample, or omit [[Run]] from the list if you want the variable to hold individual samples. For example:
+
===Object===
 +
The parameter must be the identifier of an object. This is virtually the same as the [[Function_parameter_qualifiers#Variable]] qualifier except that it can be any object, whereas <code>Variable</code> requires the object to be a variable object. Inside the function, the parameter name acts as a [[LocalAlias|local alias]] of the object itself.
  
:<code>(A: Sample[In1, Run])</code>
+
===Module===
 +
The parameter must be either the identifier of a module or an expression that computes a handle to a module. Inside the function, the parameter acts as a [[LocalAlias|local alias]] of the module object, similar to an <code>Object</code> qualifier.
  
===Index===
+
===Class===
 +
The parameter must either be the identifier of a class object (for example, the object named <code>Decision</code> which represents the class of decision nodes), or it can be an expression that computes a handle to a class object.
  
[[Function_parameter_qualifiers#Index|Index]] indicates that the parameter must be an index variable, or a [[dot-operator]] expression, such as <code>a.i</code>. You can then use the parameter as a local index within the function definition. This is useful if you want to use the index in a function that requires an index, for example <code>Sum(x, i)</code> within the function.
+
===Attribute===
 +
The parameter must either be the identifier of an Attribute (for example, <code>Description</code>), or an expression that returns a handle to an Attribute object.
  
===Var===
+
=== Expression ===
 +
The expression passed to the parameter is ''not'' evaluated, and the parsed expression is passed into the function. The function will usually evaluate the function itself under the appropriate circumstances (e.g., see [[Evaluate]]).  Because the expression is precisely the parsed expression that appears in the function call, the expression could include local variables which will no longer be within lexical scope inside the function and will not refer to anything valid in the [[UDF]]'s stack frame (or may refer to the wrong local value). Hence, this variation should not be used with [[UDF]]s if expressions containing local identifiers might be passed -- use <code>Unevaluated</code> instead.  For built-in functions, it is more efficient than <code>Unevaluated</code> and can be used because built-in functions don't create a new stack frame (mentioned here for the benefit of Lumina's internal developers).
  
[[Function_parameter_qualifiers#Variable|Variable]] or <code>Var</code> indicates that the parameter must be a variable, or the [[identifier]] of some other object. You can then treat the parameter name as equivalent to the variable, or other object name, within the function definition. This is useful if you want to use the variable in one of the few expressions or built-in functions that require a variable as a parameter, for example, [[WhatIf]], [[Dydx]], and [[Elasticity]].
+
=== Unevaluated ===
 +
The expression passed to the parameter is ''not'' evaluated, and the parsed expression is passed into the function. The function will usually evaluate the function itself under the appropriate circumstances (e.g., see [[Evaluate]]). This differs from the <code>Expression</code> qualifier in that local variables are replaced by their values in the expression. So, for example, given the UDF
 +
:Function <code>F( e : Unevaluated )</code>
 +
and the caller
 +
:<code>[[Local]] a := 5;</code>
 +
:<code>F( a^2 )</code>
 +
When the definition of F is evaluated, «e» will be the parsed expression <code>(5^2)</code> instead of <code>(local_a ^ 2)</code>.
  
==Array qualifiers==
+
==Dimension qualifiers==
  
An array or dimensionality qualifier can specify that a parameter is an array with specified index(es) or no indexes, in the case of <code>Scalar</code>.
+
A dimension or array qualifier can specify that a parameter is an array with specified index(es) or at <code>Atom</code>.or <code>Scalar</code> with no indexes,.
  
 
===Atom===
 
===Atom===
  
[[Function Parameter Qualifiers#Atom|Atom]] specifies that the parameter must be an atom — a single number, text, or other value not an array ''when the function is evaluated; but the actual parameter can be an array when you call the function''. If it is an array when you call the function, Analytica disassembles it into atoms, and evaluates the function separately on each atomic element of the array. After these evaluates, it reassembles the results into an array with the same indexes as the original parameter, and returns is returned as the overall result.
+
[[Function Parameter Qualifiers#Atom|Atom]] specifies that the parameter must be an atom — a single number, text, or other valuenot an array ''when the function is evaluated. But the actual parameter may be an array when you call the function''. If it is, Analytica disassembles the array into atoms, applies the function separately to each atom, and then reassembles the results into an array with the same indexes as the original parameter. In this way, it makes sure that the function works fine on an array-valued parameter, and fully supports [[array abstraction]] -- even though the internal definition of the function can only handle an atomic parameter value.
  
 
You need to use [[Function Parameter Qualifiers#Atom|Atom]]  only when the function uses one of Analytica’s few constructs that require an atomic parameter or operand — i.e., that does not fully support array abstraction. See [[Ensuring Array Abstraction]].
 
You need to use [[Function Parameter Qualifiers#Atom|Atom]]  only when the function uses one of Analytica’s few constructs that require an atomic parameter or operand — i.e., that does not fully support array abstraction. See [[Ensuring Array Abstraction]].
  
You might be tempted to use [[Function Parameter Qualifiers#Atom|Atom]]  to qualify parameters of every function, just in case it’s needed. We strongly advise you not to do that: Functions with [[Function Parameter Qualifiers#Atom|Atom]] parameters can take much longer to execute with array parameters, because they have to disassemble the array-valued parameters, execute the function for each atom value, and reassemble them into an array. So, avoid using it except when really necessary.
+
You might be tempted to use [[Function Parameter Qualifiers#Atom|Atom]]  to qualify parameters of every function, just in case it’s needed. But, we strongly advise against that approach: The computational time to disassemble an array parameter into Atoms, call the function multiple times, and reassemble the results can be substantial. So, avoid using it except when really necessary.
  
 
===Scalar===
 
===Scalar===
  
[[Function_parameter_qualifiers#Scalar|Scalar]] indicates that the parameter expects a single number, not an array. Means the same as <code>Number Atom</code>.
+
[[Function_parameter_qualifiers#Scalar|Scalar]] indicates that the parameter should be a single number, not an array. It means the same as <code>Number Atom</code>.
  
 
===Array[i1, i2...]===
 
===Array[i1, i2...]===
  
[[Function_parameter_qualifiers#Array|Array]] specifies that the parameter should be an array with the designated index(es) when it the function is evaluated. Similar to [[Atom]] above, you can still call the function with the parameter as an array with indexes in addition to those listed. If you do, it disassembles the array into subarrays, each with only the listed indexes. It calls the function for each subarray, so that <code>a</code> is indexed only by the specified index(es). For example, if <code>Fu1</code> has the parameter declaration:
+
'''Array''' specifies that the parameter should be an array with the designated index(es) when it the function is evaluated. The actual parameter may have indexes in addition to those listed. If so, as with '''Atom''' or '''Scalar''', it disassembles the array into subarrays, each with only the listed indexes;  applies the function to each subarray; and reassembles the results to have the original set of index(es) -- possibly excluding one or more of the listed indexes if the function reduces over the indexx. For example, if <code>Fu1</code> has the parameter declaration:
  
 
:<code>Function Fu1(a: Array[Time])</code>
 
:<code>Function Fu1(a: Array[Time])</code>
Line 117: Line 160:
 
specifies that parameter a must be an array indexed by [[Time]] (a built-in index variable) and by the index variable passed to parameter <code>j</code>.
 
specifies that parameter a must be an array indexed by [[Time]] (a built-in index variable) and by the index variable passed to parameter <code>j</code>.
  
In the absence of an array qualifier, Analytica accepts an array-valued parameter for the function, and passes it into the function <code>Definition</code> for evaluation with all its indexes. This kind of vertical array abstraction is usually more efficient for those functions that can handle array-valued parameters.
+
In the absence of an array qualifier, it accepts an array-valued parameter for the function, and passes it into the function <code>Definition</code> for evaluation with all its indexes. This kind of vertical array abstraction is usually more efficient for those functions that can handle array-valued parameters.
  
 
===All===
 
===All===
  
Forces the parameter to have, or be expanded to have, all the Indexes listed. For example:
+
[[Function_parameter_qualifiers#All|All]] forces the parameter to have, or be expanded to have, all the Indexes listed. For example:
  
 
:<code>x: All [i, j]</code>
 
:<code>x: All [i, j]</code>
  
Here the <code>All</code> qualifier forces the value of <code>x</code> to be an array indexed by the specified index variables, <code>i</code> and <code>j</code>. If <code>x</code> is a single number, not an array, <code>All</code> converts it into an array with indexes, <code>i</code> and <code>j</code>, repeating the value of <code>x</code> in each element. Without <code>All</code>, Analytica would simply pass the atomic value <code>x</code> into the function definition.
+
Here the [[Function_parameter_qualifiers#All|All]] qualifier forces the value of <code>x</code> to be an array indexed by the specified index variables, <code>i</code> and <code>j</code>. If <code>x</code> is a single number, not an array, [[Function_parameter_qualifiers#All|All]]  converts it into an array with indexes, <code>i</code> and <code>j</code>, repeating the value of <code>x</code> in each element. Without [[Function_parameter_qualifiers#All|All]] , Analytica would simply pass the atomic value <code>x</code> into the function definition.
  
==Type checking qualifiers==
+
=== Reduced ===
  
'''''Type checking qualifiers''''' make Analytica check whether the value of a parameter (each element of an array-valued parameter) has the expected type — such as, numerical, text, or reference. If any values do not have the expected type, Analytica gives an evaluation error at the time it tries to use (call) the function. The type checking qualifiers are:
+
<code>Reduced</code> is a parameter qualifier that acts in concert with Dimension qualifiers to exclude any dimensions that are being iterated. Consider, for example,
 +
 
 +
:<code>F(x: [i]; z: Reduced)</code>
 +
 
 +
Suppose you pass to parameter to «x» a value with indexes <code>[i, j]</code> and pass to parameter «z» a value with indexes <code>[j, k]</code>.  When calling function <code>F</code> the qualifier <code>[i]</code> for parameter  «x» causes the function to iterate over -- i.e. be called separately for each value of -- index <code>j</code>.  Without the <code>Reduced</code> qualifier, «z» would be indexed by <code>j</code> and <code>k</code> on each iteration, even though «x» would not have the <code>j</code> index.  By adding <code>Reduced</code> as a qualifier for «z» , it slices «z» on each iteration by <code>j</code>, but leaves «z»  indexed by <code>k</code>.
 +
 
 +
The <code>Reduced</code> qualifier is often useful when the parameter is logically atomic, but where efficiency can be gained by processing many values of «z» at the same time. For example, suppose your function <code>F</code> "fits" a curve to data «x» and returns the value of the fitted curve at «z». With reduced, it can compute the data fit only once, and then apply it to all the values of «z».
 +
 
 +
==Data Type qualifiers==
 +
 
 +
[[Function_parameter_qualifiers#Data_type_qualifiers|Type checking qualifiers]] cause a check of whether the value of a parameter (or each element of an array-valued parameter) has the expected type — such as, number, text, or reference. If any values don't have the expected type, Analytica gives an evaluation error when it tries to use (call) the function. The type checking qualifiers are:
  
 
:{| class="wikitable"
 
:{| class="wikitable"
Line 136: Line 189:
 
|-
 
|-
 
|Number
 
|Number
|A number, including <code>+INF, -INF, or NaN</code>
+
|A number, including <code>[[INF, NAN, and Null| +INF, -INF, or NaN]]</code>
 
|-
 
|-
 
|Positive
 
|Positive
| A number greater than zero, including <code>INF</code>
+
| A number greater than zero, including [[INF, NAN, and Null| <code>INF</code>]]
 
|-
 
|-
 
|Nonnegative
 
|Nonnegative
|Zero, or a number greater than zero including <code>INF</code>
+
|Zero, or a number greater than zero including [[INF, NAN, and Null| <code>INF</code>]]
 
|-
 
|-
 
|Text
 
|Text
Line 148: Line 201:
 
|-
 
|-
 
|Reference
 
|Reference
|A reference to a value, created with the \ operator
+
|A [[reference]] to a value, created with the \ operator
 
|-
 
|-
 
|Handle
 
|Handle
|A handle to an Analytica object, obtained from the <code>Handle</code> or <code>HandleFromIdentifier</code> functions. It also accepts an array of handles.
+
|A [[handle]] to an Analytica object, obtained from the <code>Handle</code> or <code>HandleFromIdentifier</code> functions. It also accepts an array of handles.
 +
|-
 +
|Color
 +
|(requires [[Analytica 5.0]]) An ARGB-integer or a [[Color parameters|textual color name]]. The value passed is always an ARGB integer.
 
|-
 
|-
 
|OrNull
 
|OrNull
|Used in conjunction with one of the above type qualifiers, allows <code>Null</code> values in addition to the given type. For example: <br />
+
|Used in conjunction with one of the above type qualifiers, allows [[INF, NAN, and Null|<code>Null</code>]]  values in addition to the given type. For example: <br />
 
<code>x: Number OrNull</code><br />
 
<code>x: Number OrNull</code><br />
Some array functions ignore <code>Null</code> values, but require this qualifier for the null values to be accepted without flagging an error.
+
Some array functions ignore [[INF, NAN, and Null|<code>Null</code>]] values, but require this qualifier for the null values to be accepted without flagging an error.  When a parameter is declared atomic and this qualifier is '''not''' specified, the function evaluation is skipped entirely and the result is null.  If you want Null to be passed into your function and the parameter is atomic, then you need to include the <code>OrNull</code> qualifier.
 
|-
 
|-
 
|Coerce
 
|Coerce
 
|If you accompany a Type checking qualifier by the <code>Coerce</code> qualifier, it tries to convert, or coerce, the value of the parameter to the specified type. For example:<br />
 
|If you accompany a Type checking qualifier by the <code>Coerce</code> qualifier, it tries to convert, or coerce, the value of the parameter to the specified type. For example:<br />
 
<code>a: Coerce Text [I]</code><br />
 
<code>a: Coerce Text [I]</code><br />
tries to convert the value of a to an array of text values. It gives an error message if any of the coercions are unsuccessful.
+
tries to convert the value of a to an array of text values. It gives an error message if any coercion is unsuccessful.
 
|}
 
|}
  
<code>Coerce</code> supports these conversions:
+
[[Function_parameter_qualifiers#Coerce_.3Ctype.3E|Coerce]] supports these conversions:
  
 
:{| class="wikitable"
 
:{| class="wikitable"
Line 196: Line 252:
 
|}
 
|}
  
Other combinations, including [[Null]] to<code> Number</code>, give an error message that the coercion is not possible.
+
Other combinations, including [[Null]] to [[Function_parameter_qualifiers#Number|Number]], give an error message that the coercion is not possible.
  
 
==Ordering qualifiers: Ascending and Descending==
 
==Ordering qualifiers: Ascending and Descending==
  
The ordering qualifiers, <code>Ascending</code> or <code>Descending</code>, check that the parameter value is an array of numbers or text values in the specified order. For text values, <code>Ascending</code> means alphabetical order, and <code>Descending</code> means the reverse.
+
The ordering qualifiers, [[Function_parameter_qualifiers#Ascending|Ascending]] or [[Function_parameter_qualifiers#Descending|Descending]], check that the parameter value is an array of numbers or text values in the specified order. For text values, [[Function_parameter_qualifiers#Ascending|Ascending]] means alphabetical order, and [[Function_parameter_qualifiers#Descending|Descending]] means the reverse.
  
 
Ordering is not strict; that is, it allows successive elements to be the same. For example, <code>[1, 2, 3, 3, 4]</code> and <code>['Anne', 'Bob', 'Bob', 'Carmen']</code> are both considered ascending.
 
Ordering is not strict; that is, it allows successive elements to be the same. For example, <code>[1, 2, 3, 3, 4]</code> and <code>['Anne', 'Bob', 'Bob', 'Carmen']</code> are both considered ascending.
Line 212: Line 268:
 
==Optional parameters==
 
==Optional parameters==
  
You can specify a parameter as optional using the qualifier <code>Optional</code>, for example:
+
You can specify a parameter as optional using the qualifier [[Function_parameter_qualifiers#Optional_qualifier|Optional]], for example:
  
 
:<code>Function F(a: Number; b: Optional Number)</code>
 
:<code>Function F(a: Number; b: Optional Number)</code>
Line 228: Line 284:
 
:<code>Function F(a: Number; b: Number Optional = 0)</code>
 
:<code>Function F(a: Number; b: Number Optional = 0)</code>
  
It uses the default value if the actual parameter is omitted. Given an equal sign and default value, the <code>Optional</code> qualifier is itself optional (!):
+
It uses the default value if the actual parameter is omitted. Given an equal sign and default value, the [[Function_parameter_qualifiers#Optional_qualifier|Optional]] qualifier is itself optional (!):
  
 
:<code>Function F(a: Number; b: Number = 0)</code>
 
:<code>Function F(a: Number; b: Number = 0)</code>
Line 261: Line 317:
 
==Repeated parameters (...)==
 
==Repeated parameters (...)==
  
Three dots, ...qualifies a parameter as repeatable, meaning that the function accepts one or more actual parameters for the formal parameter. For example:
+
Three dots, <code>...</code> qualifies a parameter as repeatable, meaning that the function accepts one or more actual parameters for the formal parameter. For example:
  
 
:<code>Function ValMax(x: ... Number) := Max(x)</code>
 
:<code>Function ValMax(x: ... Number) := Max(x)</code>
Line 277: Line 333:
 
:<code>ValMax(Sqrt(Z), Z^2, 0)</code>
 
:<code>ValMax(Sqrt(Z), Z^2, 0)</code>
  
By itself, the qualifier “...” means that the qualified parameter expects one or more parameters. If you combine “...” with <code>Optional</code>, it accepts zero or more parameters.  
+
By itself, the qualifier “...” means that the qualified parameter expects one or more parameters. If you combine “...” with [[Function_parameter_qualifiers#Optional_qualifier|Optional]], it accepts zero or more parameters.  
  
 
Calling a function that has only its last parameter repeated is easy. You just add as many parameters as you want in the call. The extra ones are treated as repeated:
 
Calling a function that has only its last parameter repeated is easy. You just add as many parameters as you want in the call. The extra ones are treated as repeated:
Line 284: Line 340:
 
:<code>F2(1, 2, 3, 4)</code>
 
:<code>F2(1, 2, 3, 4)</code>
  
Within the function, <code>F2</code>, the value of <code>a</code> is <code>1</code>, and the value of <code>b</code> is a list [2, 3, 4].
+
Within the function, <code>F2</code>, the value of <code>a</code> is <code>1</code>, and the value of <code>b</code> is a list <code>[2, 3, 4]</code>.
  
 
If the repeated parameter is not the last parameter, or if a function has more than one repeated parameter, for example:
 
If the repeated parameter is not the last parameter, or if a function has more than one repeated parameter, for example:
Line 301: Line 357:
  
 
:<code>Fxy([10, 20, 40], [2, 3, 4])</code>
 
:<code>Fxy([10, 20, 40], [2, 3, 4])</code>
 +
 +
Use [[Repeated parameter forwarding]] when you need to compute the list of parameters passed to a repeated parameter. You place three dots in front of an expression that computes a list, each item in the list being one repeat for the parameter.  The second parameter of [[Max]] is a repeated index, so this can be used to find the largest element in a multidimensional array of unknown dimensionality.
 +
:<code>[[Max]](x, ...[[IndexesOf]](x))</code>
  
 
==Deprecated synonyms for parameter qualifiers==
 
==Deprecated synonyms for parameter qualifiers==
  
Most parameter qualifiers have several synonyms. For example, <code>Atomic</code>, <code>AtomType</code>, and <code>AtomicType</code> are synonyms for <code>Atom</code>. We recommend that you use only the words listed above. If you encounter other synonyms in older models, see [[Function_Parameter_Qualifiers#Deprecated_Synonyms_for_Parameter_Qualifiers|Deprecated Synonyms for Parameter Qualifiers]].
+
Most parameter qualifiers have several synonyms. For example, <code>Atomic</code>, <code>AtomType</code>, and <code>AtomicType</code> are synonyms for [[Function_parameter_qualifiers#Atom|Atom]]. We recommend that you use only the words listed above. If you encounter other synonyms in older models, see [[Function_Parameter_Qualifiers#Deprecated_Synonyms_for_Parameter_Qualifiers|Deprecated Synonyms for Parameter Qualifiers]].
  
 
== See Also ==
 
== See Also ==

Revision as of 23:44, 28 March 2022



Parameter qualifiers are keywords used in the Parameters attribute of a function to specify what kind of value the function expects for each parameter. They include:

  • Class Qualifiers, such as Index and Variable, which specify what class of Object is expected.
  • Evaluation mode qualifiers, such as Mid and Prob, control whether to evaluate a parameter as deterministic or probabilistic.
  • Data type qualifiers, such as Number, Text, Reference, and Handle, which specify the expected data type.
  • Dimension qualifiers, such as Atom, List, Array, and [i], which specify the expected array dimensions and support array abstraction.
  • Optional and Repeated (or ...) specify whether a parameter is optional (with default value) or may be repeated.

Introducing parameter qualifiers

Parameter qualifiers help make sure that each parameter gets the kind of value or object that the function expects. They help detect or avoid errors when using System functions and User-defined functions. If the actual parameter is different from what the qualifier specifies, Analytica may be able to convert it to what was expected, or otherwise flags an error.

For example, this function returns the value of index i for which array tList indexed by i contains text matching t:

Function TextMatch(t, tList, i, caseSensitive )
Parameters: (t: Text Atom; tList: Text [i]; i: Index; caseSensitive: Boolean Atom Optional = True)
Description: If t matches a cell in tlist, a vector of text values indexed by i, it returns the value of i, otherwise Null.
By default the match is sensitive to letter case. If you specify optional parameter caseSensitive as False, it ignores the letter cases.
Definition:
If Not caseSensitive Then (
t := TextUpperCase(t);
tList := TextUpperCase(tList)
);
SubIndex( tList, t, i)

In the Parameters attribute, each parameter is followed by ":" and one or more qualifiers. The qualifier Text specifies that t and tList must contain Text values (not numbers). The dimension qualifiers [i] and Index specify that tList should have an index i, and parameter i should be the identifier of that Index. It will give an error message if i is not an Index variable. The qualifiers Boolean Optional = True specify that parameter caseSensitive should be a Boolean (True or False) and is optional. If omitted, it defaults to True -- i.e. the text match is sensitive to whether letters are upper- or lowercase.

If you write your own User-defined functions, it is important to understand at least the basics of parameter qualifiers. If not, you may find it useful when you are using built-in functions.

What you must know

If you learn about no other qualifiers, the one qualifier you need to know about is Index. You should think about it this way: some parameters are values, and some parameters are indexes. The value parameters can exist with no qualifiers, but an index parameter must have the Index qualifier. If you create a function that operates over an index, you’ll want an index qualifier.


Evaluation mode qualifiers

Evaluation modes control how, or whether, Analytica evaluates each parameter when a function is used (called). The evaluation mode qualifiers are:

Mid

Mid evaluates the parameter determinstically, or in mid mode, using the mid (usually median) of any explicit probability distribution.

Prob

Prob evaluates the parameter probabilistically, i.e., in prob mode, if it can. If you declare the dimension of the parameter, include the dimension Run in the declaration if you want the variable to hold the full sample, or omit Run from the list if you want the variable to hold individual samples. For example:

(A: Prob [In1, Run])

Sample

Sample evaluates the parameter probabilistically, i.e., in prob mode, if it can. If you declare the dimension of the parameter, include the dimension Run in the declaration if you want the variable to hold the full sample, or omit Run from the list if you want the variable to hold individual samples. For example:

(A: Sample[In1, Run])

Context

Context evaluates the parameter deterministically or probabilistically according to the current context. For example:

Function Fn1(x)
Parameters: (x: Context)
Mean(Fn1(x))

Mean() is a statistical function that always evaluates its parameter probabilistically. Hence, the evaluation context for x is probabilistic, and so Fn1 evaluates x probabilistically.

Context is the default evaluation mode used when no evaluation mode qualifier is mentioned. So, strictly, Context is redundant, and you can omit it. But, it is sometimes useful to specify it explicitly to make clear that the function should be able to handle the parameter whether it is deterministic or probabilistic.

ContextSample

ContextSample causes the qualified parameter to be evaluated in prob mode if any of the other parameters to the function are Run. If not, it evaluates in context mode — i.e., prob or mid following the context in which the function is called.

This qualifier is used for the main parameter of most built-in statistical functions. For example, Mean has these parameters:

Mean(x: ContextSample[i]; i: Index = Run)

Thus, Mean(x, Run) evaluates x in prob mode. So does Mean(x), because the index i defaults to Run. But, Mean(x, j) evaluates x in mid mode, because j is not Run.

When the parameter declaration contains more than one dimension, prob mode is used if any of the indexes is Run.


Index

Index indicates that the parameter must be an index variable, or a dot-operator expression, such as a.i. You can then use the parameter as a local index within the function definition. This is useful if you want to use the index in a function that requires an index, for example Sum(x, i) within the function.

Variable

Variable or Var indicates that the parameter must be a variable, i.e., and unquoted identifier of a variable object. You can then treat the parameter name as equivalent to the variable within the function definition. Here the parameter name is a local alias of the variable, and the variable does not get evaluated by the function call, which is different from a Context where the parameter is evaluated and the resulting value is passed in. Variable is useful if you want to use the variable in one of the few expressions or built-in functions that require a variable as a parameter, for example, WhatIf, Dydx, and Elasticity.

Object

The parameter must be the identifier of an object. This is virtually the same as the Function_parameter_qualifiers#Variable qualifier except that it can be any object, whereas Variable requires the object to be a variable object. Inside the function, the parameter name acts as a local alias of the object itself.

Module

The parameter must be either the identifier of a module or an expression that computes a handle to a module. Inside the function, the parameter acts as a local alias of the module object, similar to an Object qualifier.

Class

The parameter must either be the identifier of a class object (for example, the object named Decision which represents the class of decision nodes), or it can be an expression that computes a handle to a class object.

Attribute

The parameter must either be the identifier of an Attribute (for example, Description), or an expression that returns a handle to an Attribute object.

Expression

The expression passed to the parameter is not evaluated, and the parsed expression is passed into the function. The function will usually evaluate the function itself under the appropriate circumstances (e.g., see Evaluate). Because the expression is precisely the parsed expression that appears in the function call, the expression could include local variables which will no longer be within lexical scope inside the function and will not refer to anything valid in the UDF's stack frame (or may refer to the wrong local value). Hence, this variation should not be used with UDFs if expressions containing local identifiers might be passed -- use Unevaluated instead. For built-in functions, it is more efficient than Unevaluated and can be used because built-in functions don't create a new stack frame (mentioned here for the benefit of Lumina's internal developers).

Unevaluated

The expression passed to the parameter is not evaluated, and the parsed expression is passed into the function. The function will usually evaluate the function itself under the appropriate circumstances (e.g., see Evaluate). This differs from the Expression qualifier in that local variables are replaced by their values in the expression. So, for example, given the UDF

Function F( e : Unevaluated )

and the caller

Local a := 5;
F( a^2 )

When the definition of F is evaluated, «e» will be the parsed expression (5^2) instead of (local_a ^ 2).

Dimension qualifiers

A dimension or array qualifier can specify that a parameter is an array with specified index(es) or at Atom.or Scalar with no indexes,.

Atom

Atom specifies that the parameter must be an atom — a single number, text, or other value, not an array when the function is evaluated. But the actual parameter may be an array when you call the function. If it is, Analytica disassembles the array into atoms, applies the function separately to each atom, and then reassembles the results into an array with the same indexes as the original parameter. In this way, it makes sure that the function works fine on an array-valued parameter, and fully supports array abstraction -- even though the internal definition of the function can only handle an atomic parameter value.

You need to use Atom only when the function uses one of Analytica’s few constructs that require an atomic parameter or operand — i.e., that does not fully support array abstraction. See Ensuring Array Abstraction.

You might be tempted to use Atom to qualify parameters of every function, just in case it’s needed. But, we strongly advise against that approach: The computational time to disassemble an array parameter into Atoms, call the function multiple times, and reassemble the results can be substantial. So, avoid using it except when really necessary.

Scalar

Scalar indicates that the parameter should be a single number, not an array. It means the same as Number Atom.

Array[i1, i2...]

Array specifies that the parameter should be an array with the designated index(es) when it the function is evaluated. The actual parameter may have indexes in addition to those listed. If so, as with Atom or Scalar, it disassembles the array into subarrays, each with only the listed indexes; applies the function to each subarray; and reassembles the results to have the original set of index(es) -- possibly excluding one or more of the listed indexes if the function reduces over the indexx. For example, if Fu1 has the parameter declaration:

Function Fu1(a: Array[Time])

and if a, when evaluated, contains index(es) other than Time, it iterates over the other index(es) calling Fu1, for each one, and thus ensuring that each time it calls Fu1, parameter a has no index other than Time. See Array()

An array declaration can specified zero or more indexes between the square brackets. With zero indexes, it is equivalent to the qualifier Atom, specifying that the parameter must be a single value or atom each time the function is called.

The square brackets are sufficient and the qualifier word Array is optional, so you could write simply:

Function F(a: Number [I])

instead of

Function F(a: Number Array [I])

Each index identifier listed inside the brackets can be either a global index variable or another parameter explicitly qualified as an Index. For example the Parameters attribute:

(A: [Time, j]; j: Index)

specifies that parameter a must be an array indexed by Time (a built-in index variable) and by the index variable passed to parameter j.

In the absence of an array qualifier, it accepts an array-valued parameter for the function, and passes it into the function Definition for evaluation with all its indexes. This kind of vertical array abstraction is usually more efficient for those functions that can handle array-valued parameters.

All

All forces the parameter to have, or be expanded to have, all the Indexes listed. For example:

x: All [i, j]

Here the All qualifier forces the value of x to be an array indexed by the specified index variables, i and j. If x is a single number, not an array, All converts it into an array with indexes, i and j, repeating the value of x in each element. Without All , Analytica would simply pass the atomic value x into the function definition.

Reduced

Reduced is a parameter qualifier that acts in concert with Dimension qualifiers to exclude any dimensions that are being iterated. Consider, for example,

F(x: [i]; z: Reduced)

Suppose you pass to parameter to «x» a value with indexes [i, j] and pass to parameter «z» a value with indexes [j, k]. When calling function F the qualifier [i] for parameter «x» causes the function to iterate over -- i.e. be called separately for each value of -- index j. Without the Reduced qualifier, «z» would be indexed by j and k on each iteration, even though «x» would not have the j index. By adding Reduced as a qualifier for «z» , it slices «z» on each iteration by j, but leaves «z» indexed by k.

The Reduced qualifier is often useful when the parameter is logically atomic, but where efficiency can be gained by processing many values of «z» at the same time. For example, suppose your function F "fits" a curve to data «x» and returns the value of the fitted curve at «z». With reduced, it can compute the data fit only once, and then apply it to all the values of «z».

Data Type qualifiers

Type checking qualifiers cause a check of whether the value of a parameter (or each element of an array-valued parameter) has the expected type — such as, number, text, or reference. If any values don't have the expected type, Analytica gives an evaluation error when it tries to use (call) the function. The type checking qualifiers are:

Name Description
Number A number, including +INF, -INF, or NaN
Positive A number greater than zero, including INF
Nonnegative Zero, or a number greater than zero including INF
Text A text value
Reference A reference to a value, created with the \ operator
Handle A handle to an Analytica object, obtained from the Handle or HandleFromIdentifier functions. It also accepts an array of handles.
Color (requires Analytica 5.0) An ARGB-integer or a textual color name. The value passed is always an ARGB integer.
OrNull Used in conjunction with one of the above type qualifiers, allows Null values in addition to the given type. For example:

x: Number OrNull
Some array functions ignore Null values, but require this qualifier for the null values to be accepted without flagging an error. When a parameter is declared atomic and this qualifier is not specified, the function evaluation is skipped entirely and the result is null. If you want Null to be passed into your function and the parameter is atomic, then you need to include the OrNull qualifier.

Coerce If you accompany a Type checking qualifier by the Coerce qualifier, it tries to convert, or coerce, the value of the parameter to the specified type. For example:

a: Coerce Text [I]
tries to convert the value of a to an array of text values. It gives an error message if any coercion is unsuccessful.

Coerce supports these conversions:

From To Result
Null Text "Null"
Number Text Number as text, using the number format of the variable or function calling the function.
Text Number or Positive If possible, interprets it as a date or number, using the number format.
Null Reference \Null
Number Reference \X
Text Reference \Text

Other combinations, including Null to Number, give an error message that the coercion is not possible.

Ordering qualifiers: Ascending and Descending

The ordering qualifiers, Ascending or Descending, check that the parameter value is an array of numbers or text values in the specified order. For text values, Ascending means alphabetical order, and Descending means the reverse.

Ordering is not strict; that is, it allows successive elements to be the same. For example, [1, 2, 3, 3, 4] and ['Anne', 'Bob', 'Bob', 'Carmen'] are both considered ascending.

If the value of the parameter does not have the specified ordering, or it is an atom (not array) value, it gives an evaluation error.

If the parameter has more than one dimension (other than Run), you should specify the index of the dimension over which to check the order, for example:

A: Ascending [I]

Optional parameters

You can specify a parameter as optional using the qualifier Optional, for example:

Function F(a: Number; b: Optional Number)

In this case, you can call the function without mentioning b, as:

F(100)

Or you can specify b:

F(100, 200)

You can specify a default value for an optional parameter after an = sign, for example:

Function F(a: Number; b: Number Optional = 0)

It uses the default value if the actual parameter is omitted. Given an equal sign and default value, the Optional qualifier is itself optional (!):

Function F(a: Number; b: Number = 0)

Optional parameters can appear anywhere within the declaration — they are not limited to the final parameters. For example, if you declare the parameters for G as:

Function G(A: Optional; B; C: Optional; D; E: Optional)

You can call G in any of these ways:

G(1, 2, 3, 4, 5)
G(1, 2, , 4)
G( , 2, , 4)
G( , 2, 3, 4, 5)

Generally, you must include the commas to indicate an omitted optional parameter, before any specified parameter, but not after the last specified parameter.

Or you can use named-based calling syntax, which is usually clearer and simpler:

G(B: 2, D: 4)

IsNotSpecified](v)

If you omit a parameter that is not given a default value, you can test this inside the function definition using function IsNotSpecified(v). For example, the first line of the body of the function might read:

If IsNotSpecified(a) then a := 0;

But it is usually simpler to specify the default value in the parameter list as:

Function H(x;, a : = 0)

Repeated parameters (...)

Three dots, ... qualifies a parameter as repeatable, meaning that the function accepts one or more actual parameters for the formal parameter. For example:

Function ValMax(x: ... Number) := Max(x)
ValMax(3, 6, -2, 4) → 6

ValMax() returns the maximum value of the actual parameters given for its repeated parameter, «x». Unlike the built-in Max() function, it doesn’t need square brackets around its parameters.

During evaluation of ValMax(), the value of the repeated parameter, «x», is a list of the values of the actual parameters, with implicit (Null) index:

[3, 6, -2, 4]

ValMax() also take array parameters, for example:

Variable Z := [0.2, 0.5, 1, 2, 4]
ValMax(Sqrt(Z), Z^2, 0)

By itself, the qualifier “...” means that the qualified parameter expects one or more parameters. If you combine “...” with Optional, it accepts zero or more parameters.

Calling a function that has only its last parameter repeated is easy. You just add as many parameters as you want in the call. The extra ones are treated as repeated:

Function F2(a; b: ...)
F2(1, 2, 3, 4)

Within the function, F2, the value of a is 1, and the value of b is a list [2, 3, 4].

If the repeated parameter is not the last parameter, or if a function has more than one repeated parameter, for example:

Function Fxy(X: ... scalar; Y: ... Optional Scalar)

You have several options for syntax to call the function. Use name-based calling:

Fxy(x: 10, 20, 40, y: 2, 3, 4)

Or use position for the first repeated parameter group and name only the second parameter y:

Fxy(10, 20, 40, y: 2, 3, 4)

Or enclose each set of repeated parameters in square brackets:

Fxy([10, 20, 40], [2, 3, 4])

Use Repeated parameter forwarding when you need to compute the list of parameters passed to a repeated parameter. You place three dots in front of an expression that computes a list, each item in the list being one repeat for the parameter. The second parameter of Max is a repeated index, so this can be used to find the largest element in a multidimensional array of unknown dimensionality.

Max(x, ...IndexesOf(x))

Deprecated synonyms for parameter qualifiers

Most parameter qualifiers have several synonyms. For example, Atomic, AtomType, and AtomicType are synonyms for Atom. We recommend that you use only the words listed above. If you encounter other synonyms in older models, see Deprecated Synonyms for Parameter Qualifiers.

See Also


Comments


You are not allowed to post comments.