Defined function (traditional): Difference between revisions

From APL Wiki
Jump to navigation Jump to search
(+example to show how optional left argument is used)
m (Text replacement - "</source>" to "</syntaxhighlight>")
 
(38 intermediate revisions by 4 users not shown)
Line 1: Line 1:
A '''user-defined function''' (or '''tradfn''', for "traditional function", in [[Dyalog APL]]) is a function defined using a header that includes the function's name. Introduced in [[APL\360]], function definition was universally supported by APL dialects for much of the language's history, and is still commonly used in mainstream APLs. Since the 1990s other ways to [[Function styles|describe functions]] have appeared, with [[J]] and [[K]] rejecting function definition in favor of [[anonymous function]] description. Beginning in the 2010s [[Dyalog]]-based APL dialects including [[ngn/apl]], [[dzaima/APL]], and [[APL\iv]] have removed function definition in favor of [[dfn]]s.
:''This page is about the function form typically written with the Del (<syntaxhighlight lang=apl inline>∇</syntaxhighlight>) character. See [[Function styles]] for an overview of all forms; in particular [[dfn]]s are considered a type of defined function in [[Dyalog APL]] and [[GNU APL]].''


In many dialects the function header syntax of defined functions is adapted to allow '''defined operators''' as well.
A '''user-defined function''' (or '''tradfn''', pronounced "trad fun", for "traditional function", in [[Dyalog APL]]) is a function defined using a header that includes the function's name. Introduced in [[APL\360]], function definition was universally supported by APL dialects for much of the language's [[history]], and is still commonly used in mainstream APLs. Since the 1990s other ways to [[Function styles|describe functions]] have appeared, with [[J]] and [[K]] rejecting function definition in favor of [[anonymous function]] description.
 
{{Anchor|Representations}}The canonical representation form is equivalent to what the user would type into the [[line editor]] to define the function.<ref>[[Dyalog Ltd.]] Programming Reference Guide. [https://help.dyalog.com/latest/#Language/System%20Functions/cr.htm Canonical Representation].</ref> An alternative representation consists of the entire [[session]] log transcript, including [[Del]]s (<syntaxhighlight lang=apl inline>∇</syntaxhighlight>) and line numbers, after having such a definition has been made.<ref>[[Dyalog Ltd.]] Language Reference Guide. [https://help.dyalog.com/latest/#Language/System%20Functions/vr.htm Vector Representation].</ref> However, it should be noted that the <syntaxhighlight lang=apl inline>∇</syntaxhighlight>s are not part of the definition. Indeed, if using the [[Fix Definition]] (<syntaxhighlight lang=apl inline>⎕FX</syntaxhighlight>) [[system function]] to define the function, Dels need not (or must not, depending on implementation) be included.
 
Beginning in the 2010s [[Dyalog]]-based APL dialects including [[ngn/apl]], [[dzaima/APL]], and [[APL\iv]] have removed function definition in favor of [[dfn]]s. Wikipedia has a comparison of [[Wikipedia:Direct_function#Dfns_versus_tradfns|dfns versus tradfns]].
 
In many dialects the function header syntax of defined functions is adapted to allow user-defined [[operator]]s as well. A tradfn operator can also be called a '''tradop''' (pronounced "trad op"), parallel to how a "dfn" operator can be called a ''dop''.


== Examples ==
== Examples ==
Example function with optional left argument and one local variable:
=== Basics ===
<source lang=apl>
A simple [[dyadic function]]:
res←{left} AddMult2 right;local
<syntaxhighlight lang=apl>
  :If 0=⎕NC'left'
      r←l Tradfn r
       left←0      ⍝ define variable "left" with value 0 if it's not defined already
        ⍝ ...do something
  :EndIf
        r←l r
  local←left+right
      ∇
  res←2×local
</syntaxhighlight>
{{Works in|[[Dyalog APL]], [[APL2]], [[GNU APL]], [[NARS2000]], [[APLX]], and every older APL from [[APL\360]]}}
</source>
=== Semi-colons ===
Assignments are global by default. To keep a name local, it must be mentioned in the header, separated from the rest of the header by a semi-colon:
<syntaxhighlight lang=apl>
       ∇ r←l Tradfn r;intermediate
        intermediate←l r
        r←intermediate intermediate
     
</syntaxhighlight>
{{Works in|[[Dyalog APL]], [[APL2]], [[GNU APL]], [[NARS2000]], [[APLX]], and every older APL from [[APL\360]]}}


== Representations ==
=== Braces ===
The canonical representation form is equivalent to what the user would type into the [[line editor]] to define the function. An alternative representation consists of the entire [[session]] log transcript after having such a definition has been made. A tradfn operator can also be called a '''tradop''' (pronounced "trad op").
An [[ambivalent function]] with an optional left argument, a conditional [[control structure]], one local variable, and a [[#Shyness|shy]] result:
<syntaxhighlight lang=apl>
      ∇ {res}←{left} AddMult2 right;local
        :If 0=⎕NC'left'    ⍝ if variable "left" is not defined already
            left←0
        :EndIf
        local←left+right
        res←2×local
      ∇
      AddMult2 3    ⍝ result is "shy"
      ⎕←AddMult2 3  ⍝ coerce display of result
6
      1 AddMult2 3      ⍝ result is "shy"
      10×1 AddMult2 3  ⍝ use result anyway
80
</syntaxhighlight>
{{Works in|[[Dyalog APL]]}}
 
=== Brackets ===
[[GNU APL]] allows functions and operators to accept an [[function axis|axis]] argument:<ref>[[GNU APL community]]. GNU APL Info Manual. [https://www.gnu.org/software/apl/apl.html#Section-3_002e2 Axis argument in defined functions].</ref>
<syntaxhighlight lang=apl>
      ∇ Z←Average[X] B
        Z←(+/[X]B) ÷ (⍴B)[X]
      ∇
      Average[1] 5 5⍴⍳25
11 12 13 14 15
      Average[2] 5 5⍴⍳25
3 8 13 18 23
</syntaxhighlight>
{{Works in|[[GNU APL]]}}
=== Operators ===
A [[monadic operator]] and a [[dyadic operator]], both deriving [[monadic function]]s:
<syntaxhighlight lang=apl>
      ∇ res←(Function SELF) right
        res←right Function right
      ∇
      ×SELF 1 2 3 4 5
1 4 9 16 25
 
      ∇ res←(FunctionF HOOK FunctionG) right
        res←right FunctionF FunctionG right
      ∇
      ÷HOOK|2 0 ¯7
1 1 ¯1
</syntaxhighlight>
{{Works in|[[Dyalog APL]], [[APL2]], [[GNU APL]], [[NARS2000]], [[APLX]]}}
A monadic operator and a dyadic operator, both deriving [[dyadic function]]s:
<syntaxhighlight lang=apl>
      ∇ res←left (Function SWAP) right
        res←right Function left
      ∇
      3 2 -SWAP 10
7 8
 
      ∇ res←left (FunctionF OVER FunctionG) right
        res←(FunctionG left) FunctionF (FunctionG right)
      ∇
      2 ¯7 2+OVER|¯3 1 4
5 8 6
</syntaxhighlight>
{{Works in|[[Dyalog APL]], [[APL2]], [[GNU APL]], [[NARS2000]], [[APLX]]}}


== Properties ==
== Properties ==
Tradfns allow both functional and procedural programming, and are essential for [[object-oriented programming]]. They support a full set of [[keyword]]s for flow control and object declarations.
Tradfns allow both functional and procedural programming, and are essential for [[object-oriented programming]]. They support a full set of [[keyword]]s for flow control and object declarations.


One of the most noticeable differences from dfns is that tradfns must declare their locals, because assignments are global by default. The declaration is done in a header line which also determines the function's name and calling syntax. Tradfns cannot be nested (although a tradfn can dynamically create other tradfns by [[Fix|"fixing"]] their source, and if the function thus created has a name which has been localised, it will only exist that scope) but ''can'' contain dfns. However, nested functions are less necessary due to tradfns using [[wikipedia:dynamic scoping|dynamic scoping]] as opposed to the lexical scoping of dfns. In other words, a tradfn can "see" locals of its caller.
One of the most noticeable differences from dfns is that tradfns must declare their locals, because assignments are global by default. The declaration is done in a header line which also determines the function's name and calling syntax. [[Dyalog APL]] adds a handful of extensions this (see below).
 
Tradfns cannot be nested but ''can'' contain dfns. A tradfn can dynamically create another tradfn by [[Fix|"fixing"]] its source, and if the function thus created has a name which has been localised, the inner function will only exist the scope of the outer function. Nested functions are less necessary due to tradfns using [[wikipedia:dynamic scoping|dynamic scoping]] as opposed to the lexical scoping of dfns. In other words, a tradfn can "see" locals of its caller.


A tradfn can be [[niladic function|niladic]] which causes it to behave syntactically like an array. However, every time its name is referenced, it will run to create a result (if any). Such methods are often used to return a cache or as an entry point for the user.
A tradfn can be [[niladic function|niladic]] which causes it to behave syntactically like an array. However, every time its name is referenced, it will run to create a result (if any). Such methods are often used to return a cache or as an entry point for the user.


== A+ ==
=== Dyalog APL extensions ===
[[A+]] uses a reworked syle of function and operator definition than maintains the principle of a header that matches the way the function will be used, but differs in many details:
Dyalog APL's tradfns are enhanced in various ways compared to most other dialects.<ref>[[Dyalog Ltd.]] Programming Reference Guide. [https://help.dyalog.com/latest/#Language/Defined%20Functions%20and%20Operators/TradFns/Model%20Syntax.htm Model Syntax].</ref>
* The result name is not included in the header; instead, the result of the last executed statement is returned (and so [[niladic function]]s cannot be defined).
 
==== Dynamic localisation ====
Names can be localised dynamically, while a tradfn is running, using the [[Shadow Name]] (<syntaxhighlight lang=apl inline>⎕SHADOW</syntaxhighlight>) [[system function]].<ref>[[Dyalog Ltd.]] Language Reference Guide. [https://help.dyalog.com/latest/#Language/System%20Functions/shadow.htm Shadow Name].</ref>
<syntaxhighlight lang=apl>
      name←1 2 3
      ∇ res←Dummy
        ⎕SHADOW'name'
        name←42
        res←name
      ∇                     
      Dummy
42
      name
1 2 3
</syntaxhighlight>{{Works in|[[Dyalog APL]]}}
 
==== Locals lines ====
Additional local names can also be declared on separate lines following the header line:<ref>[[Dyalog Ltd.]] Programming Reference Guide.  [https://help.dyalog.com/latest/#Language/Defined%20Functions%20and%20Operators/TradFns/Locals%20Lines.htm Locals Lines].</ref>
<syntaxhighlight lang=apl>
      name←1 2 3
      ∇ res←Dummy
        ;name
        name←42
        res←name
      ∇                     
      Dummy
42
      name
1 2 3
</syntaxhighlight>{{Works in|[[Dyalog APL]]}}
 
==== Explicit ambivalence ====
The the header syntax can explicitly specify that a function is [[ambivalent]] by enclosing the left argument name in curly braces (for example <syntaxhighlight lang=apl inline>result←{left} Function right</syntaxhighlight>). Others dialects treat all functions that declare a left argument name as ambivalent and leave it up to the programmer to check for the presence of a value.
 
==== Function results ====
A tradfn can return a function value as result. The returned function will replace the function and its arguments (if any) in the calling expression:
<syntaxhighlight lang=apl>
      ∇ Fn←Apply name     
        :If name≡'plus'   
            Fn←+          
        :ElseIf name≡'times'
            Fn←×           
        :EndIf             
      ∇                     
      3(Apply'plus')4
7
      3(Apply'times')4
12
</syntaxhighlight>{{Works in|[[Dyalog APL]]}}
 
==== Shyness ====
By default, functions in APL will print their result to the session log even without using <syntaxhighlight lang=apl inline>⎕←</syntaxhighlight> unless their results are shy. Shy results are declared by putting curly braces around the result name (for example <syntaxhighlight lang=apl inline>{result}←left Function right</syntaxhighlight>). Assignment (<syntaxhighlight lang=apl inline>name←array</syntaxhighlight>) exhibits the same behaviour as a shy function in that, by default, no result is printed when the function terminates, but attempting to use the result still succeeds.
 
==== Namelists ====
The right argument and the result can be a name list instead of single name. The interpreter will unpack the right argument when the function is called, and collect the result when the function returns.<ref>[[Dyalog Ltd.]] Programming Reference Guide.  [https://help.dyalog.com/latest/#Language/Defined%20Functions%20and%20Operators/TradFns/Namelists.htm Namelists].</ref>
<syntaxhighlight lang=apl>
      ∇ (c b a)←Rev(a b c)
      ∇
      Rev 1 2 3
3 2 1
</syntaxhighlight>{{Works in|[[Dyalog APL]]}}
 
=== A+ differences===
[[A+]] uses a reworked style of function and operator definition than maintains the principle of a header that matches the way the function will be used, but differs in many details:
* The result name is not included in the header; instead, the result of the last executed statement is returned (and so functions that do not return a result cannot be defined).
* The header is separated from the body with a colon, and the body of a multi-line function is enclosed in curly braces.
* The header is separated from the body with a colon, and the body of a multi-line function is enclosed in curly braces.
* Functions have lexical scope. Variables assigned are local by default, and can be made global by enclosing their names in parentheses when assigning.
* Functions have lexical scope. Variables assigned are local by default, and can be made global by enclosing their names in parentheses when assigning.
== Comparison to dfns ==
Wikipedia has a comparison of [[Wikipedia:Direct_function#Dfns_versus_tradfns|dfns versus tradfns]].


==External links==
==External links==
Line 40: Line 177:


=== Documentation ===
=== Documentation ===
* [http://help.dyalog.com/latest/#Language/Defined%20Functions%20and%20Operators/Canonical%20Representation.htm#CanonicalRepresentation Dyalog]
* Dyalog: [https://help.dyalog.com/latest/#Language/Introduction/Functions.htm Functions], [https://help.dyalog.com/latest/#Language/Introduction/Operators.htm Operators]
* [http://microapl.com/apl_help/ch_020_010_070.htm APLX]
* APLX: [http://microapl.com/apl_help/ch_020_010_070.htm User-defined Functions], [http://microapl.com/apl_help/ch_020_010_090.htm User-defined Operators]
{{APL syntax}}[[Category:Kinds of functions]][[Category:Defining functions]]
 
=== References ===
<references/>
 
{{APL syntax}}
[[Category:Kinds of functions]]
[[Category:Defining functions]]

Latest revision as of 22:13, 10 September 2022

This page is about the function form typically written with the Del () character. See Function styles for an overview of all forms; in particular dfns are considered a type of defined function in Dyalog APL and GNU APL.

A user-defined function (or tradfn, pronounced "trad fun", for "traditional function", in Dyalog APL) is a function defined using a header that includes the function's name. Introduced in APL\360, function definition was universally supported by APL dialects for much of the language's history, and is still commonly used in mainstream APLs. Since the 1990s other ways to describe functions have appeared, with J and K rejecting function definition in favor of anonymous function description.

The canonical representation form is equivalent to what the user would type into the line editor to define the function.[1] An alternative representation consists of the entire session log transcript, including Dels () and line numbers, after having such a definition has been made.[2] However, it should be noted that the s are not part of the definition. Indeed, if using the Fix Definition (⎕FX) system function to define the function, Dels need not (or must not, depending on implementation) be included.

Beginning in the 2010s Dyalog-based APL dialects including ngn/apl, dzaima/APL, and APL\iv have removed function definition in favor of dfns. Wikipedia has a comparison of dfns versus tradfns.

In many dialects the function header syntax of defined functions is adapted to allow user-defined operators as well. A tradfn operator can also be called a tradop (pronounced "trad op"), parallel to how a "dfn" operator can be called a dop.

Examples

Basics

A simple dyadic function:

      ∇ r←l Tradfn r
        ⍝ ...do something
        r←l r
      ∇
Works in: Dyalog APL, APL2, GNU APL, NARS2000, APLX, and every older APL from APL\360

Semi-colons

Assignments are global by default. To keep a name local, it must be mentioned in the header, separated from the rest of the header by a semi-colon:

      ∇ r←l Tradfn r;intermediate
        intermediate←l r
        r←intermediate intermediate
      ∇
Works in: Dyalog APL, APL2, GNU APL, NARS2000, APLX, and every older APL from APL\360

Braces

An ambivalent function with an optional left argument, a conditional control structure, one local variable, and a shy result:

      ∇ {res}←{left} AddMult2 right;local
        :If 0=⎕NC'left'     ⍝ if variable "left" is not defined already
            left←0
        :EndIf
        local←left+right
        res←2×local
      ∇
      AddMult2 3     ⍝ result is "shy"
      ⎕←AddMult2 3   ⍝ coerce display of result
6
      1 AddMult2 3      ⍝ result is "shy"
      10×1 AddMult2 3   ⍝ use result anyway
80
Works in: Dyalog APL

Brackets

GNU APL allows functions and operators to accept an axis argument:[3]

      ∇ Z←Average[X] B
        Z←(+/[X]B) ÷ (⍴B)[X]
      ∇
      Average[1] 5 5⍴⍳25
11 12 13 14 15
      Average[2] 5 5⍴⍳25
3 8 13 18 23
Works in: GNU APL

Operators

A monadic operator and a dyadic operator, both deriving monadic functions:

      ∇ res←(Function SELF) right
        res←right Function right
      ∇
      ×SELF 1 2 3 4 5
1 4 9 16 25

      ∇ res←(FunctionF HOOK FunctionG) right
        res←right FunctionF FunctionG right
      ∇
      ÷HOOK|2 0 ¯7
1 1 ¯1

A monadic operator and a dyadic operator, both deriving dyadic functions:

      ∇ res←left (Function SWAP) right
        res←right Function left
      ∇
      3 2 -SWAP 10
7 8

      ∇ res←left (FunctionF OVER FunctionG) right
        res←(FunctionG left) FunctionF (FunctionG right)
      ∇
      2 ¯7 2+OVER|¯3 1 4
5 8 6

Properties

Tradfns allow both functional and procedural programming, and are essential for object-oriented programming. They support a full set of keywords for flow control and object declarations.

One of the most noticeable differences from dfns is that tradfns must declare their locals, because assignments are global by default. The declaration is done in a header line which also determines the function's name and calling syntax. Dyalog APL adds a handful of extensions this (see below).

Tradfns cannot be nested but can contain dfns. A tradfn can dynamically create another tradfn by "fixing" its source, and if the function thus created has a name which has been localised, the inner function will only exist the scope of the outer function. Nested functions are less necessary due to tradfns using dynamic scoping as opposed to the lexical scoping of dfns. In other words, a tradfn can "see" locals of its caller.

A tradfn can be niladic which causes it to behave syntactically like an array. However, every time its name is referenced, it will run to create a result (if any). Such methods are often used to return a cache or as an entry point for the user.

Dyalog APL extensions

Dyalog APL's tradfns are enhanced in various ways compared to most other dialects.[4]

Dynamic localisation

Names can be localised dynamically, while a tradfn is running, using the Shadow Name (⎕SHADOW) system function.[5]

      name←1 2 3
      ∇ res←Dummy
        ⎕SHADOW'name'
        name←42
        res←name
      ∇                      
      Dummy
42
      name
1 2 3
Works in: Dyalog APL

Locals lines

Additional local names can also be declared on separate lines following the header line:[6]

      name←1 2 3
      ∇ res←Dummy
        ;name
        name←42
        res←name
      ∇                      
      Dummy
42
      name
1 2 3
Works in: Dyalog APL

Explicit ambivalence

The the header syntax can explicitly specify that a function is ambivalent by enclosing the left argument name in curly braces (for example result←{left} Function right). Others dialects treat all functions that declare a left argument name as ambivalent and leave it up to the programmer to check for the presence of a value.

Function results

A tradfn can return a function value as result. The returned function will replace the function and its arguments (if any) in the calling expression:

      ∇ Fn←Apply name       
        :If name≡'plus'     
            Fn←+            
        :ElseIf name≡'times'
            Fn←×            
        :EndIf              
      ∇                      
      3(Apply'plus')4
7
      3(Apply'times')4
12
Works in: Dyalog APL

Shyness

By default, functions in APL will print their result to the session log even without using ⎕← unless their results are shy. Shy results are declared by putting curly braces around the result name (for example {result}←left Function right). Assignment (name←array) exhibits the same behaviour as a shy function in that, by default, no result is printed when the function terminates, but attempting to use the result still succeeds.

Namelists

The right argument and the result can be a name list instead of single name. The interpreter will unpack the right argument when the function is called, and collect the result when the function returns.[7]

      ∇ (c b a)←Rev(a b c)
      ∇
      Rev 1 2 3
3 2 1
Works in: Dyalog APL

A+ differences

A+ uses a reworked style of function and operator definition than maintains the principle of a header that matches the way the function will be used, but differs in many details:

  • The result name is not included in the header; instead, the result of the last executed statement is returned (and so functions that do not return a result cannot be defined).
  • The header is separated from the body with a colon, and the body of a multi-line function is enclosed in curly braces.
  • Functions have lexical scope. Variables assigned are local by default, and can be made global by enclosing their names in parentheses when assigning.

External links

Tutorials

Documentation

References

  1. Dyalog Ltd. Programming Reference Guide. Canonical Representation.
  2. Dyalog Ltd. Language Reference Guide. Vector Representation.
  3. GNU APL community. GNU APL Info Manual. Axis argument in defined functions.
  4. Dyalog Ltd. Programming Reference Guide. Model Syntax.
  5. Dyalog Ltd. Language Reference Guide. Shadow Name.
  6. Dyalog Ltd. Programming Reference Guide. Locals Lines.
  7. Dyalog Ltd. Programming Reference Guide. Namelists.


APL syntax [edit]
General Comparison with traditional mathematicsPrecedenceTacit programming (Train, Hook, Split composition)
Array Numeric literalStringStrand notationObject literalArray notation (design considerations)
Function ArgumentFunction valenceDerived functionDerived operatorNiladic functionMonadic functionDyadic functionAmbivalent functionDefined function (traditional)DfnFunction train
Operator OperandOperator valenceTradopDopDerived operator
Assignment MultipleIndexedSelectiveModified
Other Function axisBracket indexingBranchStatement separatorQuad nameSystem commandUser commandKeywordDot notationFunction-operator overloadingControl structureComment