Recursion
A recursive dfn can refer to itself using its name explicitly, but because we allow unnamed functions, we also need a special symbol for implicit self-reference: '∇'
. For example:
fact←{ ⍝ Factorial ⍵.
⍵≤1: 1 ⍝ Small ⍵, finished,
⍵×∇ ⍵-1 ⍝ Otherwise recur.
}
Implicit self-reference using '∇'
has the further advantage that it incurs less interpretative overhead and is therefore quicker. Tail calls using '∇'
are particularly efficient.
Recursive dops refer to their derived functions, that is the operator bound with its operand(s) using ∇
or the operator itself using the compound symbol: ∇∇
. The first form of self reference is by far the more frequently used.
pow←{ ⍝ Function power.
⍺=0:⍵ ⍝ Apply function operand ⍺ times.
(⍺-1)∇ ⍺⍺ ⍵ ⍝ ⍺⍺ ⍺⍺ ⍺⍺ ... ⍵
}
Example
The following example shows a rather contrived use of the second form of (operator) self reference. The exp
operator composes its function operand with itself on each recursive call. This gives the effect of an exponential application of the original operand function:
exp←{ ⍝ Exponential fn application.
⍺=0:⍺⍺ ⍵ ⍝ Apply operand 2*⍺ times.
(⍺-1)⍺⍺∘⍺⍺ ∇∇ ⍵ ⍝ (⍺⍺∘⍺⍺)∘( ... ) ... ⍵
}
succ←{1+⍵} ⍝ Successor (increment).
10 succ exp 0
1024
Example
∇pow←{ ⍝ Function power.
[1] ⍺=0:⍵ ⍝ Apply function operand ⍺ times.
[2] (⍺-1)∇ ⍺⍺ ⍵ ⍝ ⍺⍺ ⍺⍺ ⍺⍺ ... ⍵
[3] }
∇
4 ⍟ pow 5000
¯0.2720968003
Example: Pythagorean triples
The following sequence shows an example of combining dfns and dops in an attempt to find Pythagorean triples: (3 4 5)(5 12 13)
...
sqrt←{⍵*0.5} ⍝ Square root.
sqrt 9 16 25
3 4 5
hyp←{sqrt+/⊃⍵*2} ⍝ Hypoteneuse of triangle.
hyp(3 4)(4 5)(5 12)
5 6.403124237 13
intg←{⍵=⌊⍵} ⍝ Whole number?
intg 2.5 3 4.5
0 1 0
pyth←{intg hyp ⍵} ⍝ Pythagorean pair?
pyth(3 4)(4 9)(5 12)
1 0 1
pairs←{,⍳⍵ ⍵} ⍝ Pairs of numbers 1..⍵.
pairs 3
1 1 1 2 1 3 2 1 2 2 2 3 3 1 3 2 3 3
filter←{(⍺⍺ ⍵)/⍵} ⍝ Op: ⍵ filtered by ⍺⍺.
pyth filter pairs 12 ⍝ Pythagorean pairs 1..12
3 4 4 3 5 12 6 8 8 6 9 12 12 5 12 9
So far, so good, but we have some duplicates: (6 8)
is just double (3 4)
.
rpm←{ ⍝ Relatively prime?
⍵=0:⍺=1 ⍝ C.f. Euclid's gcd.
⍵ ∇ ⍵|⍺
}/¨ ⍝ Note the /¨
rpm(2 4)(3 4)(6 8)(16 27)
0 1 0 1
rpm filter pyth filter pairs 20
3 4 4 3 5 12 8 15 12 5 15 8
We can use an operator to combine the tests:
and←{ ⍝ Lazy parallel 'And'.
mask←⍺⍺ ⍵ ⍝ Left predicate selects...
mask\⍵⍵ mask/⍵ ⍝ args for right predicate.
}
pyth and rpm filter pairs 20
3 4 4 3 5 12 8 15 12 5 15 8
Better, but we still have some duplicates: (3 4) (4 3)
less←{</⊃⍵}
less(3 4)(4 3)
1 0
less and pyth and rpm filter pairs 40
3 4 5 12 7 24 8 15 9 40 12 35 20 21
And finally, as promised, triples:
{⍵,hyp ⍵}¨less and pyth and rpm filter pairs 35
3 4 5 5 12 13 7 24 25 8 15 17 12 35 37 20 21 29
A Larger Example
Function tokens
uses nested local dfns to split an APL expression into its constituent tokens. Note that all calls on the inner functions: lex, acc
, and the unnamed dfn in each token case, are tail calls. In fact, the only stack calls are those on function: all
, and the unnamed function: {⍵∨¯1⌽⍵}
, within the "Char literal" case.
tokens←{ ⍝ Lex of APL src line.
alph←⎕A,⎕Á,'_∆⍙',26↑17↓⎕AV ⍝ Alphabet for names.
all←{+/^\⍺∊⍵} ⍝ No. of leading ⍺∊⍵.
acc←{(⍺,↑/⍵)lex⊃↓/⍵} ⍝ Accumulate tokens.
lex←{
0=⍴⍵:⍺ ⋄ hd←↑⍵ ⍝ Next char else done.
hd=' ':⍺{ ⍝ White Space.
size←⍵ all' '
⍺ acc size ⍵
}⍵
hd∊alph:⍺{ ⍝ Name
size←⍵ all alph,⎕D
⍺ acc size ⍵
}⍵
hd∊'⎕:':⍺{ ⍝ System Name/Keyword
size←⍵ all hd,alph
⍺ acc size ⍵
}⍵
hd='''':⍺{ ⍝ Char literal
size←+/^\{⍵∨¯1⌽⍵}≠\hd=⍵
⍺ acc size ⍵
}⍵
hd∊⎕D,'¯':⍺{ ⍝ Numeric literal
size←⍵ all ⎕D,'.¯E'
⍺ acc size ⍵
}⍵
hd='⍝':⍺ acc(⍴⍵)⍵ ⍝ Comment
⍺ acc 1 ⍵ ⍝ Single char token.
}
(0⍴⊂'')lex,⍵
}
display tokens'xtok←size↑srce ⍝ Next token'
.→-------------------------------------------------.
| .→---. .→. .→---. .→. .→---. .→-. .→-----------. |
| |xtok| |←| |size| |↑| |srce| | | |⍝ Next token| |
| '----' '-' '----' '-' '----' '--' '------------' |
'∊-------------------------------------------------'