User-Defined Functions/Operators/Hyperators

From NARS2000
Revision as of 19:40, 13 February 2015 by Robert Wallick (talk | contribs) (added context to operators)
Jump to navigationJump to search
  • User-defined Functions and Operators

    • Within a user-defined function/operator header, the left and right arguments may consist of one or more names each separated by one or more blanks and enclosed in parentheses. In this context, the caller of the function/operator must pass a scalar (which is extended to each name) or an appropriate length vector argument. Upon invocation of the function/operator, these values are assigned one item per name.

      For example, a function whose header looks like

      ∇ Z←FOO (R1 R2)

      can be called with a two-element vector (or a scalar which is extended to a two-element vector) right argument only. If the right argument is of rank greater than one, a RANK ERROR is signaled. If the right argument is not of the proper length, a LENGTH ERROR is signaled.

      Note that if only one name appears within parentheses in the left or right argument, the caller must supply a value for this argument which is a scalar or one-element vector.

    • Within a user-defined function/operator header, the result may consist of two or more names each separated by one or more blanks and enclosed in parentheses. In this context, when the function exits, the individual names must all have a value (else a VALUE ERROR is signaled), the names are joined together in a strand, and the resulting vector is returned as the result. If the header contains only one name for the result, it may not be enclosed in parentheses.

    • Thanks to Dyalog APL for proposing and implementing the above features.

    • Within a user-defined function/operator header, the result may be marked as shy or non-displayable by enclosing it in braces, as in ∇ {Z}←FOO R. If the result part of the header consists of multiple names, either
      ∇ {Z1 Z2}←FOO R,
      ∇ ({Z1 Z2})←FOO R, or
      ∇ {(Z1 Z2)}←FOO R
      may be used to mark the result as shy.

    • Within a user-defined function/operator header, the left argument may be marked as optional (a.k.a. ambivalent) by enclosing it in braces, as in ∇ Z←{L} FOO R. If the left argument part of the header consists of multiple names, either
      ∇ Z←{L1 L2} FOO R     ⍝TWO optional left arguments
      ∇ Z←({L1 L2}) FOO R
      ∇ Z←{(L1 L2)} FOO R
      Braces {} are used to mark the left argument as optional. System function ⎕NC may be used to detect the presence/absence of a braced{noncompulsory} left argument(0=Not Used/Missing Arg, 2=Used/Yes Arg - for {ArgName} e.g. {L} by calling   ⎕NC 'L'   within the user function itself, here FOO).

    • A user-defined function/operator may accept the axis operator as an additional argument, just as primitive function/operators do. The axis operator may be specified in the header as in
      ∇ Z←FOO[X] R for a function,
      ∇ Z←(LO FOO[X]) R for a monadic operator, and
      ∇ Z←(LO FOO[X] RO) R for a dyadic operator.

    • A user-defined function/operator may define a separate entry point for when it is called on a prototype — use the line label ⎕PRO:. For example, the monadic function FOO when used in FOO¨R where R is an empty array is entered at the line labeled ⎕PRO:. If there is no such line with that label, a DOMAIN ERROR is signaled.
  • User-defined Operators

    • A user-defined operator is distinguished from a user-defined function by its header, such that in the place where the function name normally appears, it contains a left operand name, an operator name, and an optional right operand name (for dyadic operators only), all enclosed in a single set of parentheses. For example, the operator part of the header for a monadic operator looks like (LO MonOp), and a dyadic operator looks like (LO DydOp RO) where LO and RO are the left and right operands (functions).

      Both types of user-defined operators may be called monadically or dyadically, as in

      Monadic derived function Dyadic derived function
      Monadic operator ∇ Z←(LO MonOp) R ∇ Z←L (LO MonOp) R
      Dyadic operator ∇ Z←(LO DydOp RO) R ∇ Z←L (LO DydOp RO) R

      Operators exist to modify behaviors of functions as well as operate on data. An operator may be applied to a function to derive a different function or modify data(/\+-×÷). An attribute of operators are their precedence over functions; operators are executed before functions. One indication an Operator should be used instead of a function is - when a function always includes parentheses during its call. Proper structuring of commonly used operators prevents, for instance, multiple layers of parentheses, thus clarifying code, speeding execution and increasing parallelization. Operator usage situations: Statisticians - regression operators (power, multiple, growth, natural, cubic, cylical, etc.); Astronomers - integration and differentiation operators; Engineers - curve fitting, approximating, equation root derivations.

      Just like user-defined functions, user-defined operators may have multiple names in the result, left, and right arguments (but not the left and/or right operands), an optional left argument, an axis operator, and a non-displayable result.

      A header using all these features might look like

      ∇ {(Z1 Z2)}←{(L1 L2 L3)} (LO DydOp[X] RO) (R1 R2 R3 R4)

    • A jot () may be used as an operand to a user-defined operator in which case the corresponding name in the header is undefined, that is ⎕NC returns 0. For example,

          ∇ (Z1 Z2)←(LO DydOp RO) R
      [1]   :select ⍬⍴⎕NC 'LO'
      [2]   :case 0 ⋄ Z1←'LO is undefined'
      [3]   :case 2 ⋄ Z1←'LO is a variable'
      [4]   :case 3 ⋄ Z1←'LO is a function'
      [5]   :end
      [6]
      [7]   :select ⍬⍴⎕NC 'RO'
      [8]   :case 0 ⋄ Z2←'RO is undefined'
      [9]   :case 2 ⋄ Z2←'RO is a variable'
      [10]  :case 3 ⋄ Z2←'RO is a function'
      [11]  :end
          ∇

            ∘DydOp⍴ 12
      LO is undefined  RO is a function
            ⍴DydOp∘ 12
      LO is a function  RO is undefined
            ∘DydOp∘ 12
      LO is undefined  RO is undefined