Direct function: Difference between revisions

Content deleted Content added
Roger Hui (talk | contribs)
Multiple recursion: added reference to Hardy & Ramanujan 1918
OAbot (talk | contribs)
m Open access bot: url-access updated in citation with #oabot.
 
(32 intermediate revisions by 19 users not shown)
Line 1:
{{Short description|Alternate way to define a function in APL}}
{{redirect|Dfns|the political entity sometimes known as the Democratic Federation of Northern Syria|RojavaAutonomous Administration of North and East Syria}}
A '''direct function''' ('''dfn''', pronounced "dee fun") is an alternative way to define a function and operator (a [[higher-order function]]) in the programming language [[APL (programming language)|APL]]. A direct operator can also be called a '''dop''' (pronounced "dee op"). They were invented by [[John M. Scholes|John Scholes]] in 1996.<ref name=Scholes1996>{{cite journal|last=Scholes|first=John|title=Direct Functions in Dyalog APL|journal=Vector|volume=13|number=2|date=October 1996|url=http://www.dyalog.com/uploads/documents/Papers/dfns.pdf|access-date=16 September 2019}}</ref> They are a unique combination of [[array programming]], higher-order function, and [[functional programming]], and are a major distinguishing advance of early 21st century APL over prior versions.
 
A dfn is a sequence of possibly [[Guard (computer science)|guarded expressions]] (or just a guard) between {{code|{|apl}} and {{code|}|apl}}, separated by {{code|⋄|apl}} or new-lines, wherein {{code|⍺|apl}} denotes the left argument and {{code|⍵|apl}} the right, and {{code|∇|apl}} denotes [[Recursion (computer science)|recursion]] (function self-reference). For example, the function {{code|PT|apl}} tests whether each row of {{code|⍵|apl}} is a [[Pythagorean triplet]] (by testing whether the sum of squares equals twice the square of the maximum).
 
<sourcesyntaxhighlight lang=apl>
PT← {(+/⍵*2)=2×(⌈/⍵)*2}
PT 3 4 5
Line 17 ⟶ 18:
PT x
1 0 1 0 0 1
</syntaxhighlight>
</source>
 
{{Anchor|factorial}}
The [[factorial]] function as a dfn:
 
<sourcesyntaxhighlight lang=apl>
fact← {0=⍵:1 ⋄ ⍵×∇ ⍵-1}
fact 5
Line 28 ⟶ 29:
fact¨ ⍳10 ⍝ fact applied to each element of 0 to 9
1 1 2 6 24 120 720 5040 40320 362880
</syntaxhighlight>
</source>
 
== Description ==
The rules for dfns are summarized by the following "reference card":<ref name=refcard>{{citation|last=Scholes|first=John|title=Direct Functions Reference Card|date=1998-20191998–2019|url=http://dfns.dyalog.com/n_refcard|access-date=26 September 2019}}{{Dead link|date=February 2024 |bot=InternetArchiveBot |fix-attempted=yes }}</ref>
 
{| class="wikitable"
Line 56 ⟶ 57:
 
A dfn is a sequence of possibly [[Guard (computer science)|guarded expressions]] (or just a guard) between {{code|{|apl}} and {{code|}|apl}}, separated by {{code|⋄|apl}} or new-lines.
<sourcesyntaxhighlight lang=apl>
expression
guard: expression
guard:
</syntaxhighlight>
</source>
The expressions and/or guards are evaluated in sequence. A guard must evaluate to a 0 or 1; its associated expression is evaluated if the value is 1. A dfn terminates after the first unguarded expression which does not end in [[Assignment (computer science)|assignment]], or after the first guarded expression whose guard evaluates to 1, or if there are no more expressions. The result of a dfn is that of the last evaluated expression. If that last evaluated expression ends in assignment, the result is "shy"—not automatically displayed in the session.
 
Line 76 ⟶ 77:
 
== Examples ==
The examples here illustrate different aspects of dfns. Additional examples are found in the cited articles.<ref name=dfnsWS>{{citation|last=Scholes|first=John|title=Direct Functions Workspace|date=1998-20191998–2019|url=http://dfns.dyalog.com|access-date=2019-09-15}}</ref><ref name=APL1978/><ref name=history50>{{citation|last=Hui|first=Roger|author-link=Roger Hui|title=A History of APL in 50 Functions|date=27 November 2016|url=http://www.jsoftware.com/papers/50|access-date=17 September 2019}}</ref>
 
=== Default left argument ===
The function {{code|{⍺+0j1×⍵}|apl}} adds {{code|⍺|apl}} to {{code|0j1|apl}} ({{mvar|i}} or {{<math|>\sqrt{{sqrt|−1}}}-1}</math>) times {{code|⍵|apl}}.
 
<sourcesyntaxhighlight lang=apl>
3 {⍺+0j1×⍵} 4
3J4
Line 90 ⟶ 91:
1J¯2 1J¯1 1 1J1 1J2
2J¯2 2J¯1 2 2J1 2J2
</syntaxhighlight>
</source>
 
The significance of this function can be seen as follows:
 
{{quoteblockquote|Complex numbers can be constructed as ordered pairs of real numbers, similar to how integers can be constructed as ordered pairs of natural numbers and rational numbers as ordered pairs of integers. For complex numbers, {{code|{⍺+0j1×⍵}|apl}} plays the same role as {{code|-|apl}} for integers and {{code|÷|apl}} for rational numbers.<ref name=Hui2016/>{{rp|§8}}}}
 
Moreover, analogous to that monadic {{code|-⍵|apl}} &hArr; {{code|0-⍵|apl}} (''negate'') and monadic {{code|÷⍵|apl}} &hArr; {{code|1÷⍵|apl}} (''reciprocal''), a monadic definition of the function is useful, effected by specifying a default value of 0 for {{code|⍺|apl}}: if {{code|j←{⍺←0 ⋄ ⍺+0j1×⍵}|apl}}, then {{code|j ⍵|apl}} &hArr; {{code|0 j ⍵|apl}} &hArr; {{code|0+0j1×⍵|apl}}.
 
<sourcesyntaxhighlight lang=apl>
j←{⍺←0 ⋄ ⍺+0j1×⍵}
 
Line 113 ⟶ 114:
Euler (¯0.5+?10⍴0) j (¯0.5+?10⍴0)
1 1 1 1 1 1 1 1 1 1
</syntaxhighlight>
</source>
 
The last expression illustrates [[Euler's formula]] on ten random numbers with real and imaginary parts in the interval <math>\left(-0.5,0.5\right)</math>.
Line 129 ⟶ 130:
The Cantor set of order {{code|⍵|apl}} defined as a dfn:<ref name=Hui2016>{{citation|last=Hui|first=Roger|author-link=Roger Hui|title=APL Exercises|date=18 July 2016|url=http://www.jsoftware.com/papers/APL_exercises/|access-date=24 September 2019}}</ref>{{rp|§2.5}}
 
<sourcesyntaxhighlight lang=apl>
Cantor← {0=⍵:,1 ⋄ ,1 0 1 ∘.∧ ∇ ⍵-1}
 
Line 140 ⟶ 141:
Cantor 3
1 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 1
</syntaxhighlight>
</source>
 
Cantor 0 to Cantor 6 depicted as black bars:
Line 149 ⟶ 150:
The function {{code|sieve ⍵|apl}} computes a bit vector of length {{code|⍵|apl}} so that bit {{code|i|apl}} (for {{code|0≤i|apl}} and {{code|i<⍵|apl}}) is 1 if and only if {{code|i|apl}} is a [[Prime number|prime]].<ref name=history50/>{{rp|§46}}
 
<sourcesyntaxhighlight lang=apl>
sieve←{
4≥⍵:⍵⍴0 0 1 1
Line 176 ⟶ 177:
(10*⍳10) (+⌿↑)⍤0 1 ⊢b
0 4 25 168 1229 9592 78498 664579 5761455 50847534
</syntaxhighlight>
</source>
 
The last sequence, the number of primes less than powers of 10, is an initial segment of {{OEIS2C|id=A006880}}. The last number, 50847534, is the number of primes less than <math>10^9</math>. It is called Bertelsen's number, memorably described by [[MathWorld]] as "an erroneous name erroneously given the erroneous value of <math>\pi(10^9) = 50847478</math>".<ref name=MathWorld>{{citation|last=Weisstein|first=Eric W.|title=Bertelsen's Number|publisher=MathWorld, A Wolfram Web Resource|url=http://mathworld.wolfram.com/BertelsensNumber.html|access-date=26 September 2019}}</ref>
Line 183 ⟶ 184:
 
=== Tail recursion ===
Typically, the [[factorial]] function is define recursively (as [[#factorial|above]]), but it can be coded to exploit [[tail call|tail recursion]] by using an accumulator left argument:<ref name=fact>{{citation|last=Scholes|first=John|title=Factorial|date=1998-20191998–2019|journal=DfnsDFNS workspaceWorkspace|url=http://dfns.dyalog.com/n_factorial.htm|access-date=20 September 2019}}</ref>
<sourcesyntaxhighlight lang=apl>
fac←{⍺←1 ⋄ ⍵=0:⍺ ⋄ (⍺×⍵) ∇ ⍵-1}
</syntaxhighlight>
</source>
 
Similarly, the [[determinant]] of a square complex matrix using [[Gaussian elimination]] can be computed with tail recursion:<ref name=det>{{citation|last=Scholes|first=John|title=Determinant|date=1998-20191998–2019|journal=DfnsDFNS workspaceWorkspace|url=http://dfns.dyalog.com/n_det.htm|access-date=20 September 2019}}</ref>
<sourcesyntaxhighlight lang=apl>
det←{ ⍝ determinant of a square complex matrix
⍺←1 ⍝ product of co-factor coefficients so far
Line 197 ⟶ 198:
(⍺×⍵[i;j]ׯ1*i+j) ∇ ⍵[k~i;k~j] - ⍵[k~i;j] ∘.× ⍵[i;k~j]÷⍵[i;j]
}
</syntaxhighlight>
</source>
 
=== Multiple recursion ===
A [[PartitionInteger (number theory)partition|partition]] of a non-negative integer <math>n</math> is a vector <math>v</math> of positive integers such that {{code|n {{=}} +⌿v|apl}}, where the order in <math>v</math> is not significant. For example, {{code|2 2|apl}} and {{code|2 1 1|apl}} are partitions of 4, and {{code|2 1 1|apl}} and {{code|1 2 1|apl}} and {{code|1 1 2|apl}} are considered to be the same partition.
 
The [[Partition function (number theory)|partition function]] <math>P(n)</math> counts the number of partitions. The function is of interest in [[number theory]], studied by [[Leonhard Euler|Euler]], [[G. H. Hardy|Hardy]], [[Srinivasa Ramanujan|Ramanujan]], [[Paul Erdős|Erdős]], and others. The recurrence relation
 
:<math>P(n)=\sum_{k=1}^n (-1)^{k+1}[P(n-\frac{1}{2}k(3k-1))+P(n-\frac{1}{2}k(3k+1))]</math>
 
derived from Euler's [[pentagonal number theorem]].<ref name=MathWorldP>{{citation|last=Weisstein|first=Eric W.|title=Partition Function P, equation 11|publisher=MathWorld, A Wolfram Web Resource|url=http://mathworld.wolfram.com/PartitionFunctionP.html|access-date=3 October 2019}}</ref> Written as a dfn:<ref name=history50/>{{rp|§16}}
 
<sourcesyntaxhighlight lang=apl>
pn ← {1≥⍵:0≤⍵ ⋄ -⌿+⌿∇¨rec ⍵}
rec ← {⍵ - (÷∘2 (×⍤1) ¯1 1 ∘.+ 3∘×) 1+⍳⌈0.5*⍨⍵×2÷3}
Line 216 ⟶ 217:
pn¨ ⍳13 ⍝ OEIS A000041
1 1 2 3 5 7 11 15 22 30 42 56 77
</syntaxhighlight>
</source>
 
The basis step {{code|1≥⍵:0≤⍵|apl}} states that for {{code|1≥⍵|apl}}, the result of the function is {{code|0≤⍵|apl}}, 1 if ⍵ is 0 or 1 and 0 otherwise. The recursive step is highly multiply recursive. For example, {{code|pn 200|apl}} would result in the function being applied to each element of {{code|rec 200|apl}}, which are:
 
<sourcesyntaxhighlight lang=apl>
rec 200
199 195 188 178 165 149 130 108 83 55 24 ¯10
198 193 185 174 160 143 123 100 74 45 13 ¯22
</syntaxhighlight>
</source>
 
and {{code|pn 200|apl}} requires longer than the [[age of the universe]] to compute (<math>7.57\times10^{47}</math> function calls to itself).<ref name=history50/>{{rp|§16}} The compute time can be reduced by [[memoization]], here implemented as the direct operator (higher-order function) {{code|M|apl}}:
 
<sourcesyntaxhighlight lang=apl>
M←{
f←⍺⍺
Line 239 ⟶ 240:
0 ⍕ pn M 200 ⍝ format to 0 decimal places
3972999029388
</syntaxhighlight>
</source>
 
This value of {{code|pn M 200|apl}} agrees with that computed by Hardy and Ramanujan in 1918.<ref>{{citation|last1=Hardy|first1=G.H.|last2=Ramanujan|first2=S.|title= Asymptotic Formulæ in Combinatory Analysis|journal=Proceedings of the London MathematicsMathematical Society|volume=17|number=2|date=1918|url=http://ramanujan.sirinudi.org/Volumes/published/ram36.pdf|access-date=24 December 2019}}</ref>
 
The memo operator {{code|M|apl}} defines a variant of its operand function {{code|⍺⍺|apl}} to use a [[Cache (computing)|cache]] {{code|T|apl}} and then evaluates it. With the operand {{code|pn|apl}} the variant is:
 
<sourcesyntaxhighlight lang=apl>
{T←(1+⍵)⍴¯1 ⋄ {1≥⍵:0≤⍵ ⋄ ¯1≢T[⍵]:⊃T[⍵] ⋄ ⊃T[⍵]←⊂-⌿+⌿∇¨rec ⍵}⍵}
</syntaxhighlight>
</source>
 
=== Direct operator (dop) ===
[[Quicksort]] on an array {{code|⍵|apl}} works by choosing a "pivot" at random among its major cells, then catenating the sorted major cells which strictly precede the pivot, the major cells equal to the pivot, and the sorted major cells which strictly follow the pivot, as determined by a comparison function {{code|⍺⍺|apl}}. Defined as a direct [[Higher-order function|operator]] (dop) {{code|Q|apl}}:
<sourcesyntaxhighlight lang=apl>
Q←{1≥≢⍵:⍵ ⋄ (∇ ⍵⌿⍨0>s)⍪(⍵⌿⍨0=s)⍪∇ ⍵⌿⍨0<s←⍵ ⍺⍺ ⍵⌷⍨?≢⍵}
 
Line 262 ⟶ 263:
(×-) Q x
0 2 3 3 4 6 7 8 9 10 14 15 19 19
</syntaxhighlight>
</source>
 
{{code|Q3|apl}} is a variant that catenates the three parts enclosed by the function {{code|⊂|apl}} instead of the parts ''per se''. The three parts generated at each recursive step are apparent in the structure of the final result. Applying the function derived from {{code|Q3|apl}} to the same argument multiple times gives different results because the pivots are chosen at random. [[Tree traversal#In-order, (LNR)|In-order traversal]] of the results does yield the same sorted array.
<sourcesyntaxhighlight lang=apl>
Q3←{1≥≢⍵:⍵ ⋄ (⊂∇ ⍵⌿⍨0>s)⍪(⊂⍵⌿⍨0=s)⍪⊂∇ ⍵⌿⍨0<s←⍵ ⍺⍺ ⍵⌷⍨?≢⍵}
 
Line 294 ⟶ 295:
│└┴─┴──────────────────────┘│ │ │
└───────────────────────────┴─┴─────────────────────────────┘
</syntaxhighlight>
</source>
 
The above formulation is not new; see for example Figure 3.7 of the classic ''The Design and Analysis of Computer Algorithms''.<ref name=AHU>{{citation|lastlast1=Aho|firstfirst1=A.V.|author-link=Alfred Aho|last2=Hopcroft|first2=J.E.|author-link2=John Hopcroft|last3=Ullman|first3=J.D.|author-link3=Jeffrey Ullman|title=The Design and Analysis of Computer Algorithms|date=1974|publisher=Addison-Wesley|bibcode=1974daca.book.....A }}</ref> However, unlike the [[Pidgin code|pidgin]] [[ALGOL]] program in Figure 3.7, {{code|Q|apl}} is executable, and the partial order used in the sorting is an operand, the {{code|(×-)|apl}} the examples above.<ref name=APL1978/>
 
=== Dfns with operators and trains ===
Dfns, especially anonymous dfns, work well with operators and trains. The following snippet solves a "Programming Pearls" puzzle:<ref name=Bentley1983>{{cite journal|last=Bentley|first=Jon|title=Programming Pearls|journal=[[Communications of the ACM]]|volume=26|number=8 and 9|date=August 1983}}</ref> given a dictionary of English words, here represented as the character matrix {{code|a|apl}}, find all sets of anagrams.
 
<sourcesyntaxhighlight lang=apl>
a {⍵[⍋⍵]}⍤1 ⊢a ({⍵[⍋⍵]}⍤1 {⊂⍵}⌸ ⊢) a
pats apst ┌────┬────┬────┐
Line 316 ⟶ 317:
east aest
seta aest
</syntaxhighlight>
</source>
 
The algorithm works by sorting the rows individually ({{code|{⍵[⍋⍵]}⍤1 ⊢a|apl}}), and these sorted rows are used as keys ("signature" in the Programming Pearls description) to the ''key'' operator {{code|⌸|apl}} to group the rows of the matrix.<ref name=APL1978/>{{rp|§3.3}} The expression on the right is a ''train'', a syntactic form employed by APL to achieve [[tacit programming]]. Here, it is an isolated sequence of three functions such that {{code|(f g h) ⍵|apl}} &hArr; {{code|(f ⍵) g (h ⍵)|apl}}, whence the expression on the right is equivalent to {{code|({⍵[⍋⍵]}⍤1 ⊢a) {⊂⍵}⌸ a|apl}}.
 
=== Lexical scope ===
Line 325 ⟶ 326:
For example, in the following function {{code|which|apl}}, the variable {{code|ty|apl}} is defined both in {{code|which|apl}} itself and in the inner function {{code|f1|apl}}. When {{code|f1|apl}} calls outward to {{code|f2|apl}} and {{code|f2|apl}} refers to {{code|ty|apl}}, it finds the outer one (with value {{code|'lexical'|apl}}) rather than the one defined in {{code|f1|apl}} (with value {{code|'dynamic'|apl}}):
 
<sourcesyntaxhighlight lang=apl>
which←{
ty←'lexical'
Line 335 ⟶ 336:
which ' scope'
lexical scope
</syntaxhighlight>
</source>
 
=== Error-guard ===
The following function illustrates use of error guards:<ref name=Dyalog17.1/>{{rp|p.139}}
<sourcesyntaxhighlight lang=apl>
plus←{
tx←'catch all' ⋄ 0::tx
Line 354 ⟶ 355:
2 3 plus 3 4⍴5 ⍝ can't add vector to matrix
catch all
</syntaxhighlight>
</source>
 
In APL, error number 5 is "length error"; error number 11 is "___domain error"; and error number 0 is a "catch all" for error numbers 1 to 999.
Line 364 ⟶ 365:
 
{| class="wikitable"
|- bgcolorstyle="vertical-align:top; background-color:#ffffff;"
| {{sxhl|1=
|-
|- bgcolor="#ffffff"
| <pre>
sieve←{
4≥⍵:⍵⍴0 0 1 1
Line 376 ⟶ 375:
{r<q←b⍳1:b⊣b[⍵]←1 ⋄ b[q,q×⍸b↑⍨⌈n÷q]←0 ⋄ ∇ ⍵,q}p
}
|2=apl}}
 
| {{sxhl|1=
 
 
 
 
 
 
 
</pre>
| <pre>
∇ b←sieve1 n;i;m;p;q;r
:If 4≥n ⋄ b←n⍴0 0 1 1 ⋄ :Return ⋄ :EndIf
Line 397 ⟶ 388:
b[p]←1
|2=apl}}
 
| {{sxhl|1=
 
 
 
 
</pre>
| <pre>
∇ b←sieve2 n;i;m;p;q;r
→L10 ⍴⍨ 4<n ⋄ b←n⍴0 0 1 1 ⋄ →0
Line 420 ⟶ 406:
b[p]←1
|2=apl}}
</pre>
|}
 
Line 433 ⟶ 419:
* [[Recursion (computer science)|Recursion]] in a dfn is effected by invoking {{code|∇|apl}} or {{code|∇∇|apl}} or its name; recursion in a tradfn is effected by invoking its name.
* [[Control flow|Flow control]] in a dfn is effected by guards and function calls; that in a tradfn is by control structures and {{code|→|apl}} (goto) and line labels.
* AEvaluating linean expression in a dfn not ending in assignment causes return from the dfn; evaluating a line in a tradfn not ending in assignment or goto displays the result of the line.
* A dfn returns on aevaluating linean expression not ending in assignment, on evaluating a guarded expression, or after the last lineexpression; a tradfn returns on {{code|→|apl}} (goto) line 0 or a non-existing line, or on evaluating a {{code|:Return|apl}} control structure, or after the last line.
* The simpler flow control in a dfn makes it easier to detect and implement [[Tail call|tail recursion]] than in a tradfn.
* A dfn may call a tradfn and ''vice versa''; a dfn may be defined in a tradfn, and ''vice versa''.
 
== History ==
[[Kenneth E. Iverson]], the inventor of APL, was dissatisfied with the way user functions (tradfns) were defined. In 1974, he devised "formal function definition" or "direct definition" for use in exposition.<ref name=directdef>{{citation|last=Iverson|first=Kenneth E.|author-link=Kenneth E. Iverson|title=Elementary Functions|chapter=Chapter 10, Formal Function Definition|date=1974|publisher=IBM Corporation|chapter-url=http://www.jsoftware.com/papers/DirectDef.htm|access-date=18 September 2019}}</ref> A direct definition has two or four parts, separated by colons:
<sourcesyntaxhighlight lang=apl>
name : expression
name : expression0 : proposition : expression1
</syntaxhighlight>
</source>
Within a direct definition, {{code|⍺|apl}} denotes the left argument and {{code|⍵|apl}} the right argument. In the first instance, the result of {{code|expression|apl}} is the result of the function; in the second instance, the result of the function is that of {{code|expression0|apl}} if {{code|proposition|apl}} evaluates to 0, or {{code|expression1|apl}} if it evaluates to 1. Assignments within a direct definition are [[Scope (computer science)#Dynamic scoping|dynamically local]]. Examples of using direct definition are found in the 1979 [[Turing Award]] Lecture<ref name=TOT>{{cite journal|last=Iverson|first=Kenneth E.|author-link=Kenneth E. Iverson|title=Notation as a Tool of Thought|journal=[[Communications of the ACM]]|volume=23|number=8|date=August 1980|url=https://www.jsoftware.com/papers/tot.htm|access-date=8 April 2016|doi=10.1145/358896.358899|pages=444–465|doi-access=free}}</ref> and in books and application papers.<ref name=Iverson1976>{{cite book|last=Iverson|first=Kenneth E.|author-link=Kenneth E. Iverson|title=Elementary Analysis|publisher=APL Press|date=1976}}</ref><ref name=Orth1976>{{cite book|last=Orth|first=D.L.|title=Calculus in a New Key|publisher=APL Press|date=1976}}</ref><ref name=Hui1987>{{cite journal|last=Hui|first=Roger|author-link=Roger Hui|title=Some Uses of { and }|journal=APL 87 Conference Proceedings|date=May 1987|url=http://www.jsoftware.com/papers/from.htm|access-date=15 April 2016}}</ref><ref name=McDonnell1987>{{citation|last=McDonnell|first=E.E.|title=Life: Nasty, Brutish, and Short|journal=APL 87 Conference Proceedings|date=May 1987|url=http://www.jsoftware/papers/EEM/life.htm|access-date=6 October 2019}}{{Dead link|date=May 2023 |bot=InternetArchiveBot |fix-attempted=yes }}</ref><ref name=APL1978>{{citationcite journal|lastlast1=Hui|firstfirst1=Roger|author-link=Roger Hui|last2=Kromberg|first2=Morten|title=APL Since 1978|journal=Proceedings of the ACM on Programming Languages|volume=4|number=HOPL|date=June 2020|pages=1–108|doi=10.1145/3386319|s2cid=218517570|doi-access=free}}</ref>
 
Direct definition was too limited for use in larger systems. The ideas were further developed by multiple authors in multiple works<ref name=opfns>{{citation|last=Iverson|first=Kenneth E.|author-link=Kenneth E. Iverson|title=Operators and Functions|journal=Research Report Number #RC7091|date=26 April 1978|publisher=IBM Corporation|url=http://www.jsoftware.com/papers/opfns.htm|access-date=2019-09-19}}</ref>{{rp|§8}}<ref name=IversonWooster1981>{{cite journal|lastlast1=Iverson|firstfirst1=Kenneth E.|author-link=Kenneth E. Iverson|last2=Wooster|first2=Peter|title=A Function Definition Operator|journal=APL81 Conference Proceedings, APL Quote Quad|volume=12|number=1|date=September 1981}}</ref><ref name=Cheney>{{citation|last=Cheney|first=Carl M.|title=APL*Plus Nested Array System Reference Manual|date=March 1981|publisher=[[Scientific Time Sharing Corporation|STSC, Inc.]]|url=http://www.sudleyplace.com/APL/Nested%20Arrays%20System.pdf|access-date=18 September 2019}}</ref>{{rp|§4.17}}<ref name=ratapl>{{citation|last=Iverson|first=Kenneth E.|author-link=Kenneth E. Iverson|title=Rationalized APL|date=6 January 1983|publisher=[[I. P. Sharp Associates]]|url=http://www.jsoftware.com/papers/RationalizedAPL.htm|access-date=2019-09-19}}</ref><ref name=dictionary>{{cite journal|last=Iverson|first=Kenneth E.|author-link=Kenneth E. Iverson|title=A Dictionary of APL|journal=APL Quote Quad|volume=18|number=1|date=September 1987|pages=5–40|doi=10.1145/36983.36984|s2cid=18301178|url=http://www.jsoftware.com/papers/APLDictionary.htm|access-date=19 September 2019|url-access=subscription}}</ref><ref name=Bunda1987>{{cite journal|last=Bunda|first=John|title=APL Function Definition Notation|journal=APL87 Conference Proceedings, APL Quote Quad|volume=17|number=4|date=May 1987}}</ref><ref name=J>{{cite journalbook|last=Hui|first=Roger|title=Conference proceedings on APL 90: For the future |chapter=APL\? |author-link=Roger Hui|display-authors=etal|title=APL\?|journal=APL90 Conference Proceedings, APL Quote Quad|volume=20|number=4|date=July 1990|pages=192–200|doi=10.1145/97808.97845|isbn=089791371X|s2cid=235453656 |chapter-url=http://www.jsoftware.com/papers/J1990.htm|access-date=2019-09-10}}</ref> but the results were unwieldy. Of these, the "alternative APL function definition" of Bunda in 1987<ref name=Bunda1987/> came closest to current facilities, but is flawed in conflicts with existing symbols and in error handling which would have caused practical difficulties, and was never implemented. The main distillates from the different proposals were that (a) the function being defined is anonymous, with subsequent naming (if required) being effected by assignment; (b) the function is denoted by a symbol and thereby enables [[anonymous recursion]].<ref name=APL1978/>
 
In 1996, [[John M. Scholes|John Scholes]] of Dyalog Limited invented direct functions (dfns).<ref name=Scholes1996/><ref name=Scholes2018v/><ref name=Scholes2018t/> The ideas originated in 1989 when he read a special issue of ''[[The Computer Journal]]'' on functional programming.<ref name=Wadler>{{cite journal|last=Wadler|first=Philip L.|display-authors=etal|title=Special Issue on Functional Programming|journal=[[The Computer Journal]]|volume=32|number=2|date=1 January 1989}}</ref> He then proceeded to study functional programming and became strongly motivated ("sick with desire", like [[W. B. Yeats|Yeats]]) to bring these ideas to APL.<ref name=Scholes2018v/><ref name=Scholes2018t/> He initially operated in stealth because he was concerned the changes might be judged too radical and an unnecessary complication of the language; other observers say that he operated in stealth because Dyalog colleagues were not so enamored and thought he was wasting his time and causing trouble for people. Dfns were first presented in the Dyalog Vendor Forum at the APL '96 Conference in [[San Antonio]] and released in Dyalog APL in early 1997.<ref name=Scholes1996/> Acceptance and recognition were slow in coming. As late as 2008, in ''Dyalog at 25'',<ref name=Dyalog@25>{{cite journal|last=Dyalog|title=Dyalog at 25|journal=Vector|date=September 2008|url=http://www.dyalog.com/uploads/documents/dyalog_25.pdf|access-date=2019-09-20}}</ref> a publication celebrating the 25th anniversary of Dyalog Limited, dfns were barely mentioned (mentioned twice as "dynamic functions" and without elaboration). As{{as of |2019}}, dfns are implemented in Dyalog APL,<ref name=Dyalog17.1/> NARS2000,<ref name=NARS2000>{{citation|last=Smith|first=Bob|title=NARS2000|date=2006-20192006–2019|url=http://www.nars2000.org/|access-date=18 September 2019}}</ref> and ngn/apl.<ref name=Nickolov2013>{{cite journal|last=Nickolov|first=Nick|title=Compiling APL to JavaScript|journal=Vector|volume=26|number=1|date=September 2013|url=http://archive.vector.org.uk/art10501160|access-date=19 September 2019}}</ref> They also play a key role in efforts to exploit the computing abilities of a [[graphics processing unit]] (GPU).<ref name=Hsu2019>{{cite thesis|last=Hsu|first=Aaron|title=A Data Parallel Compiler Hosted on a GPU (pre-print draft)|degree=Ph.D.|institution=[[Indiana University]]|date=2019|url=http://scholarworks.iu.edu/dspace/bitstream/handle/2022/24749/Hsu%20Dissertation.pdf|access-date=25 December 2019}}</ref><ref name=APL1978>{{citation|last=Hui|first=Roger|author-link=Roger Hui|last2=Kromberg|first2=Morten|title=APL Since 1978|date=June 2020}}</ref>
 
== References ==