Directe functie - Direct function
Een directe functie ( dfn , uitgesproken als "dee fun") is een alternatieve manier om een functie en operator (een functie van hogere orde ) te definiëren in de programmeertaal APL . Een directe operator kan ook een dop worden genoemd (uitgesproken als "dee op"). Ze werden uitgevonden door John Scholes in 1996. Ze zijn een unieke combinatie van array-programmering , hogere-orde-functie en functionele programmering , en zijn een belangrijke onderscheidende vooruitgang van de vroege 21e-eeuwse APL ten opzichte van eerdere versies.
Een dfn is een reeks van mogelijk bewaakte uitdrukkingen (of alleen een bewaker) tussen {en }, gescheiden door ⋄of nieuwe regels, waarbij ⍺het linkerargument en ⍵het rechterargument worden aangegeven, en recursie (functie-zelfreferentie) ∇aangeeft . De functie test bijvoorbeeld of elke rij van een Pythagoras triplet is (door te testen of de som van de kwadraten gelijk is aan tweemaal het kwadraat van het maximum).
PT⍵
PT← {(+/⍵*2)=2×(⌈/⍵)*2}
PT 3 4 5
1
x
4 5 3
3 11 6
5 13 12
17 16 8
11 12 4
17 15 8
PT x
1 0 1 0 0 1
De faculteitsfunctie als een dfn:
fact← {0=⍵:1 ⋄ ⍵×∇ ⍵-1}
fact 5
120
fact¨ ⍳10 ⍝ fact applied to each element of 0 to 9
1 1 2 6 24 120 720 5040 40320 362880
Beschrijving
De regels voor dfns worden samengevat door de volgende "referentiekaart":
{⍺ function ⍵}
|
{⍺⍺ operator ⍵⍵}
|
: bewaker
|
⍺ links argument
|
⍺⍺ linker operand
|
:: foutbewaker
|
⍵ juiste argument
|
⍵⍵ rechter operand
|
⍺← standaard links argument
|
∇ zelfverwijzing
|
∇∇ zelfverwijzing
|
s← verlegen resultaat
|
Een dfn is een opeenvolging van mogelijk bewaakte uitdrukkingen (of alleen een bewaker) tussen {en }, gescheiden door ⋄of nieuwe regels.
expression
guard: expression
guard:
De uitdrukkingen en/of bewakers worden in volgorde geëvalueerd. Een bewaker moet evalueren naar een 0 of 1; de bijbehorende expressie wordt geëvalueerd als de waarde 1 is. Een dfn eindigt na de eerste onbewaakte expressie die niet eindigt op toewijzing , of na de eerste bewaakte expressie waarvan de guard evalueert tot 1, of als er geen expressies meer zijn. Het resultaat van een dfn is dat van de laatst geëvalueerde uitdrukking. Als die laatst geëvalueerde uitdrukking eindigt in een toewijzing, is het resultaat 'verlegen' en wordt niet automatisch weergegeven in de sessie.
Namen die in een dfn zijn toegewezen, zijn standaard lokaal , met lexicale scope .
⍺geeft het linker functieargument aan en ⍵het rechter; ⍺⍺geeft de linker operand en ⍵⍵de rechter aan. Als het ⍵⍵voorkomt in de definitie, dan is de dfn een dyadische operator ; als alleen ⍺⍺voorkomt maar niet ⍵⍵, dan is het een monadische operator; als geen van beide ⍺⍺of ⍵⍵voorkomt, dan is de dfn een functie.
De speciale syntaxis wordt gebruikt om een standaardwaarde aan het linkerargument te geven als een dfn monadisch wordt aangeroepen, dat wil zeggen zonder linkerargument. Het wordt niet anders beoordeeld.
⍺←expression⍺←expression
∇geeft recursie of zelfverwijzing door de functie aan en ∇∇geeft zelfverwijzing door de operator aan. Een dergelijke aanduiding maakt anonieme recursie mogelijk .
Error trapping wordt geleverd door middel van error-guards, . Wanneer een fout wordt gegenereerd, zoekt het systeem dynamisch door de aanroepende functies naar een foutbeveiliging die overeenkomt met de fout. Als er een wordt gevonden, wordt de uitvoeringsomgeving afgewikkeld naar de toestand onmiddellijk voorafgaand aan de uitvoering van de error-guard en wordt de bijbehorende expressie van de error-guard geëvalueerd als het resultaat van de dfn.
errnums::expression
Aanvullende beschrijvingen, uitleg en tutorials over dfns zijn beschikbaar in de geciteerde artikelen.
Voorbeelden
De voorbeelden hier illustreren verschillende aspecten van dfns. Aanvullende voorbeelden zijn te vinden in de geciteerde artikelen.
Standaard links argument
De functie voegt aan ( i of √ -1 ) maal .
{⍺+0j1×⍵}⍺0j1⍵
3 {⍺+0j1×⍵} 4
3J4
∘.{⍺+0j1×⍵}⍨ ¯2+⍳5
¯2J¯2 ¯2J¯1 ¯2 ¯2J1 ¯2J2
¯1J¯2 ¯1J¯1 ¯1 ¯1J1 ¯1J2
0J¯2 0J¯1 0 0J1 0J2
1J¯2 1J¯1 1 1J1 1J2
2J¯2 2J¯1 2 2J1 2J2
De betekenis van deze functie kan als volgt worden gezien:
Complexe getallen kunnen worden geconstrueerd als geordende paren van reële getallen, vergelijkbaar met hoe gehele getallen kunnen worden geconstrueerd als geordende paren natuurlijke getallen en rationale getallen als geordende paren van gehele getallen. Voor complexe getallen speelt dezelfde rol als voor gehele getallen en voor rationale getallen.
{⍺+0j1×⍵}-÷
Bovendien, analoog aan die monadische ⇔ ( negate ) en monadic ⇔ ( reciproke ), is een monadische definitie van de functie nuttig, bewerkstelligd door een standaardwaarde van 0 op te geven voor : if , then ⇔ ⇔ .
-⍵0-⍵÷⍵1÷⍵⍺j←{⍺←0 ⋄ ⍺+0j1×⍵}j ⍵0 j ⍵0+0j1×⍵
j←{⍺←0 ⋄ ⍺+0j1×⍵}
3 j 4 ¯5.6 7.89
3J4 3J¯5.6 3J7.89
j 4 ¯5.6 7.89
0J4 0J¯5.6 0J7.89
sin← 1∘○
cos← 2∘○
Euler← {(*j ⍵) = (cos ⍵) j (sin ⍵)}
Euler (¯0.5+?10⍴0) j (¯0.5+?10⍴0)
1 1 1 1 1 1 1 1 1 1
De laatste uitdrukking illustreert de formule van Euler op tien willekeurige getallen met reële en imaginaire delen in het interval .
Enkele recursie
De ternaire constructie van de Cantor-verzameling begint met het interval [0,1] en verwijdert in elke fase het middelste derde deel van elk overblijvend subinterval:
De Cantor- ⍵ordereeks gedefinieerd als een dfn:
Cantor← {0=⍵:,1 ⋄ ,1 0 1 ∘.∧ ∇ ⍵-1}
Cantor 0
1
Cantor 1
1 0 1
Cantor 2
1 0 1 0 0 0 1 0 1
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
Cantor 0 t/m Cantor 6 weergegeven als zwarte balken:
De functie berekent een bitvector van lengte zodat bit (voor en ) 1 is als en slechts als een priemgetal is .
sieve ⍵⍵i0≤ii<⍵i
sieve←{
4≥⍵:⍵⍴0 0 1 1
r←⌊0.5*⍨n←⍵
p←2 3 5 7 11 13 17 19 23 29 31 37 41 43
p←(1+(n≤×⍀p)⍳1)↑p
b← 0@1 ⊃ {(m⍴⍵)>m⍴⍺↑1 ⊣ m←n⌊⍺×≢⍵}⌿ ⊖1,p
{r<q←b⍳1:b⊣b[⍵]←1 ⋄ b[q,q×⍸b↑⍨⌈n÷q]←0 ⋄ ∇ ⍵,q}p
}
10 10 ⍴ sieve 100
0 0 1 1 0 1 0 1 0 0
0 1 0 1 0 0 0 1 0 1
0 0 0 1 0 0 0 0 0 1
0 1 0 0 0 0 0 1 0 0
0 1 0 1 0 0 0 1 0 0
0 0 0 1 0 0 0 0 0 1
0 1 0 0 0 0 0 1 0 0
0 1 0 1 0 0 0 0 0 1
0 0 0 1 0 0 0 0 0 1
0 0 0 0 0 0 0 1 0 0
b←sieve 1e9
≢b
1000000000
(10*⍳10) (+⌿↑)⍤0 1 ⊢b
0 4 25 168 1229 9592 78498 664579 5761455 50847534
De laatste reeks, het aantal priemgetallen kleiner dan machten van 10, is een eerste segment van OEIS : A006880 . Het laatste getal, 50847534, is het aantal priemgetallen kleiner dan . Het wordt het getal van Bertelsen genoemd, memorabel beschreven door MathWorld als "een foutieve naam die ten onrechte de foutieve waarde van " heeft gekregen.
sievegebruik van twee verschillende methoden voor markering composieten met 0s, beide uitgevoerd met lokale anonieme dfns: De eerste toepassingen van de zeef van Eratosthenes van een eerste masker 1 en een prefix van de priemgetallen 2 3 ... 43, met het inzetstuk operator ⌿( rechts vouwen ). (De lengte van het voorvoegsel wordt verkregen in vergelijking met de oerfunctie .) De tweede vindt het kleinste nieuwe priemgetal dat overblijft in ( ), en stelt zichzelf in op 0 bit en bits soms de getallen op de resterende 1 bits in een initieel segment van ( ) . Deze tweede dfn gebruikt staartrecursie.
×⍀pqbq←b⍳1qqb⍸b↑⍨⌈n÷q
staart recursie
Meestal wordt de faculteitsfunctie recursief gedefinieerd (zoals hierboven ), maar deze kan worden gecodeerd om staartrecursie te exploiteren door een accumulator-links argument te gebruiken:
fac←{⍺←1 ⋄ ⍵=0:⍺ ⋄ (⍺×⍵) ∇ ⍵-1}
Evenzo kan de determinant van een vierkante complexe matrix met behulp van Gauss-eliminatie worden berekend met staartrecursie:
det←{ ⍝ determinant of a square complex matrix
⍺←1 ⍝ product of co-factor coefficients so far
0=≢⍵:⍺ ⍝ result for 0-by-0
(i j)←(⍴⍵)⊤⊃⍒|,⍵ ⍝ row and column index of the maximal element
k←⍳≢⍵
(⍺×⍵[i;j]ׯ1*i+j) ∇ ⍵[k~i;k~j] - ⍵[k~i;j] ∘.× ⍵[i;k~j]÷⍵[i;j]
}
Meerdere recursie
Een partitie van een niet-negatief geheel getal is een vector van positieve gehele getallen zodat , waarbij de volgorde in niet significant is. Bijvoorbeeld, en zijn partities van 4, en en en worden beschouwd als dezelfde partitie.
n = +⌿v2 22 1 12 1 11 2 11 1 2
De partitiefunctie telt het aantal partities. De functie is van belang in de getaltheorie , bestudeerd door Euler , Hardy , Ramanujan , Erdős en anderen. De herhalingsrelatie
afgeleid van de vijfhoekige getalstelling van Euler . Geschreven als een dfn:
pn ← {1≥⍵:0≤⍵ ⋄ -⌿+⌿∇¨rec ⍵}
rec ← {⍵ - (÷∘2 (×⍤1) ¯1 1 ∘.+ 3∘×) 1+⍳⌈0.5*⍨⍵×2÷3}
pn 10
42
pn¨ ⍳13 ⍝ OEIS A000041
1 1 2 3 5 7 11 15 22 30 42 56 77
De basisstap stelt dat voor , het resultaat van de functie is , 1 als ⍵ 0 of 1 is en anders 0. De recursieve stap is sterk vermenigvuldigd recursief. Zou er bijvoorbeeld toe leiden dat de functie wordt toegepast op elk element van , namelijk:
1≥⍵:0≤⍵1≥⍵0≤⍵pn 200rec 200
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
en vereist meer dan de leeftijd van het universum om te berekenen ( functieaanroepen naar zichzelf). De rekentijd kan worden verminderd door geheugenopslag , hier geïmplementeerd als de directe operator (functie van hogere orde) :
pn 200M
M←{
f←⍺⍺
i←2+'⋄'⍳⍨t←2↓,⎕cr 'f'
⍎'{T←(1+⍵)⍴¯1 ⋄ ',(i↑t),'¯1≢T[⍵]:⊃T[⍵] ⋄ ⊃T[⍵]←⊂',(i↓t),'⍵}⍵'
}
pn M 200
3.973E12
0 ⍕ pn M 200 ⍝ format to 0 decimal places
3972999029388
Deze waarde komt overeen met die berekend door Hardy en Ramanujan in 1918.
pn M 200
De memo-operator Mdefinieert een variant van zijn operandfunctie ⍺⍺om een cache te gebruiken Ten evalueert deze vervolgens. Met de operand is pnde variant:
{T←(1+⍵)⍴¯1 ⋄ {1≥⍵:0≤⍵ ⋄ ¯1≢T[⍵]:⊃T[⍵] ⋄ ⊃T[⍵]←⊂-⌿+⌿∇¨rec ⍵}⍵}
Directe operator (dop)
Quicksort op een array ⍵werkt door willekeurig een "draaipunt" te kiezen uit de belangrijkste cellen, en vervolgens de gesorteerde hoofdcellen die strikt voorafgaan aan het draaipunt, de hoofdcellen gelijk aan het draaipunt en de gesorteerde hoofdcellen die strikt het draaipunt volgen, te rangschikken, zoals bepaald door een vergelijkingsfunctie ⍺⍺. Gedefinieerd als een directe operator (dop) Q:
Q←{1≥≢⍵:⍵ ⋄ (∇ ⍵⌿⍨0>s)⍪(⍵⌿⍨0=s)⍪∇ ⍵⌿⍨0<s←⍵ ⍺⍺ ⍵⌷⍨?≢⍵}
⍝ precedes ⍝ follows ⍝ equals
2 (×-) 8 8 (×-) 2 8 (×-) 8
¯1 1 0
x← 2 19 3 8 3 6 9 4 19 7 0 10 15 14
(×-) Q x
0 2 3 3 4 6 7 8 9 10 14 15 19 19
Q3is een variant die de drie delen omvat die door de functie worden omsloten in ⊂plaats van de delen per se . De drie delen die bij elke recursieve stap worden gegenereerd, zijn duidelijk zichtbaar in de structuur van het eindresultaat. Het Q3meerdere keren toepassen van de functie die is afgeleid van hetzelfde argument geeft verschillende resultaten omdat de pivots willekeurig worden gekozen. Het op volgorde doorlopen van de resultaten levert dezelfde gesorteerde array op.
Q3←{1≥≢⍵:⍵ ⋄ (⊂∇ ⍵⌿⍨0>s)⍪(⊂⍵⌿⍨0=s)⍪⊂∇ ⍵⌿⍨0<s←⍵ ⍺⍺ ⍵⌷⍨?≢⍵}
(×-) Q3 x
┌────────────────────────────────────────────┬─────┬┐
│┌──────────────┬─┬─────────────────────────┐│19 19││
││┌──────┬───┬─┐│6│┌──────┬─┬──────────────┐││ ││
│││┌┬─┬─┐│3 3│4││ ││┌┬─┬─┐│9│┌┬──┬────────┐│││ ││
│││││0│2││ │ ││ ││││7│8││ │││10│┌──┬──┬┐││││ ││
│││└┴─┴─┘│ │ ││ ││└┴─┴─┘│ │││ ││14│15││││││ ││
││└──────┴───┴─┘│ ││ │ │││ │└──┴──┴┘││││ ││
││ │ ││ │ │└┴──┴────────┘│││ ││
││ │ │└──────┴─┴──────────────┘││ ││
│└──────────────┴─┴─────────────────────────┘│ ││
└────────────────────────────────────────────┴─────┴┘
(×-) Q3 x
┌───────────────────────────┬─┬─────────────────────────────┐
│┌┬─┬──────────────────────┐│7│┌────────────────────┬─────┬┐│
│││0│┌┬─┬─────────────────┐││ ││┌──────┬──┬────────┐│19 19│││
│││ │││2│┌────────────┬─┬┐│││ │││┌┬─┬─┐│10│┌──┬──┬┐││ │││
│││ │││ ││┌───────┬─┬┐│6│││││ │││││8│9││ ││14│15││││ │││
│││ │││ │││┌┬───┬┐│4│││ │││││ │││└┴─┴─┘│ │└──┴──┴┘││ │││
│││ │││ │││││3 3│││ │││ │││││ ││└──────┴──┴────────┘│ │││
│││ │││ │││└┴───┴┘│ │││ │││││ │└────────────────────┴─────┴┘│
│││ │││ ││└───────┴─┴┘│ │││││ │ │
│││ │││ │└────────────┴─┴┘│││ │ │
│││ │└┴─┴─────────────────┘││ │ │
│└┴─┴──────────────────────┘│ │ │
└───────────────────────────┴─┴─────────────────────────────┘
Bovenstaande formulering is niet nieuw; zie bijvoorbeeld figuur 3.7 van de klassieker The Design and Analysis of Computer Algorithms . In tegenstelling tot het pidgin- programma ALGOL in figuur 3.7, Qis het echter uitvoerbaar, en de gedeeltelijke volgorde die bij het sorteren wordt gebruikt, is een operand, zoals in de bovenstaande voorbeelden.
(×-)
Dfns met operators en treinen
Dfns, vooral anonieme dfns, werken goed met operators en treinen. Het volgende fragment lost een "Programming Pearls"-puzzel op: gegeven een woordenboek met Engelse woorden, hier weergegeven als de karaktermatrix a, vind je alle sets anagrammen.
a {⍵[⍋⍵]}⍤1 ⊢a ({⍵[⍋⍵]}⍤1 {⊂⍵}⌸ ⊢) a
pats apst ┌────┬────┬────┐
spat apst │pats│teas│star│
teas aest │spat│sate│ │
sate aest │taps│etas│ │
taps apst │past│seat│ │
etas aest │ │eats│ │
past apst │ │tase│ │
seat aest │ │east│ │
eats aest │ │seta│ │
tase aest └────┴────┴────┘
star arst
east aest
seta aest
Het algoritme werkt door de rijen afzonderlijk te sorteren ( ), en deze gesorteerde rijen worden gebruikt als sleutels ("handtekening" in de programmeerparelsbeschrijving) voor de key- operator om de rijen van de matrix te groeperen. De uitdrukking aan de rechterkant is een trein , een syntactische vorm die door APL wordt gebruikt om stilzwijgende programmering te bereiken . Hier is het een geïsoleerde reeks van drie functies zodat ⇔ , vanwaar de uitdrukking aan de rechterkant gelijk is aan .
{⍵[⍋⍵]}⍤1 ⊢a⌸(f g h) ⍵(f ⍵) g (h ⍵)({⍵[⍋⍵]}⍤1 ⊢a) {⊂⍵}⌸ a
Lexicale reikwijdte
Wanneer een innerlijke (geneste) dfn naar een naam verwijst, wordt deze gezocht door naar buiten te kijken door de omsluitende dfns in plaats van langs de call-stack . Dit regime zou lexicale reikwijdte gebruiken in plaats van de gebruikelijke dynamische reikwijdte van APL . Het onderscheid wordt pas duidelijk als er een aanroep wordt gedaan naar een functie die op een extern niveau is gedefinieerd. Voor de meer gebruikelijke inkomende oproepen zijn de twee regimes niet te onderscheiden.
In de volgende functie whichis de variabele tybijvoorbeeld zowel in whichzichzelf als in de innerlijke functie gedefinieerd f1. Wanneer f1naar buiten wordt aangeroepen f2en f2verwijst naar ty, wordt de buitenste (met waarde 'lexical') gevonden in plaats van degene die is gedefinieerd in f1(met waarde 'dynamic'):
which←{
ty←'lexical'
f1←{ty←'dynamic' ⋄ f2 ⍵}
f2←{ty,⍵}
f1 ⍵
}
which ' scope'
lexical scope
Foutbewaking
De volgende functie illustreert het gebruik van foutbeveiligingen:
plus←{
tx←'catch all' ⋄ 0::tx
tx←'domain' ⋄ 11::tx
tx←'length' ⋄ 5::tx
⍺+⍵
}
2 plus 3 ⍝ no errors
5
2 3 4 5 plus 'three' ⍝ argument lengths don't match
length
2 3 4 5 plus 'four' ⍝ can't add characters
domain
2 3 plus 3 4⍴5 ⍝ can't add vector to matrix
catch all
In APL is foutnummer 5 "lengtefout"; foutnummer 11 is "domeinfout"; en foutnummer 0 is een "catch all" voor foutnummers 1 tot 999.
Het voorbeeld toont het afwikkelen van de lokale omgeving voordat de expressie van een error-guard wordt geëvalueerd. De lokale naam txis ingesteld om de reikwijdte van de volgende foutbeveiliging te beschrijven. Wanneer er een fout optreedt, wordt de omgeving afgewikkeld om txde statisch correcte waarde weer te geven.
Dfns versus tradfns
Aangezien directe functies dfns zijn, worden APL-functies die op de traditionele manier zijn gedefinieerd, tradfns genoemd, uitgesproken als "trad funs". Hier worden dfns en tradfns vergeleken door rekening te houden met de functie sieve: Aan de linkerkant is een dfn (zoals hierboven gedefinieerd ); in het midden is een tradfn die controlestructuren gebruikt ; aan de rechterkant is een tradfn met behulp van GOTO's ( →) en lijn labels .
sieve←{
4≥⍵:⍵⍴0 0 1 1
r←⌊0.5*⍨n←⍵
p←2 3 5 7 11 13 17 19 23 29 31 37 41 43
p←(1+(n≤×⍀p)⍳1)↑p
b← 0@1 ⊃ {(m⍴⍵)>m⍴⍺↑1 ⊣ m←n⌊⍺×≢⍵}⌿ ⊖1,p
{r<q←b⍳1:b⊣b[⍵]←1 ⋄ b[q,q×⍸b↑⍨⌈n÷q]←0 ⋄ ∇ ⍵,q}p
}
|
∇ b←sieve1 n;i;m;p;q;r :If 4≥n ⋄ b←n⍴0 0 1 1 ⋄ :Return ⋄ :EndIf r←⌊0.5*⍨n p←2 3 5 7 11 13 17 19 23 29 31 37 41 43 p←(1+(n≤×⍀p)⍳1)↑p b←1 :For q :In p ⋄ b←(m⍴b)>m⍴q↑1 ⊣ m←n⌊q×≢b ⋄ :EndFor b[1]←0 :While r≥q←b⍳1 ⋄ b[q,q×⍸b↑⍨⌈n÷q]←0 ⋄ p⍪←q ⋄ :EndWhile b[p]←1 ∇ |
∇ b←sieve2 n;i;m;p;q;r →L10 ⍴⍨ 4<n ⋄ b←n⍴0 0 1 1 ⋄ →0 L10: r←⌊0.5*⍨n p←2 3 5 7 11 13 17 19 23 29 31 37 41 43 p←(1+(n≤×\p)⍳1)↑p i←0 ⋄ b←1 L20: b←(m⍴b)>m⍴p[i]↑1 ⊣ m←n⌊p[i]×≢b →L20 ⍴⍨ (≢p)>i←1+i b[1]←0 L30: →L40 ⍴⍨ r<q←b⍳1 ⋄ b[q,q×⍸b↑⍨⌈n÷q]←0 ⋄ p⍪←q ⋄ →L30 L40: b[p]←1 ∇ |
- Een dfn kan anoniem zijn ; er moet een tradfn worden genoemd.
- Een dfn wordt genoemd door toewijzing (
←); een tradfn wordt benoemd door de naam in de representatie van de functie in te bedden en⎕fx(een systeemfunctie) op die representatie toe te passen. - Een dfn is handiger dan een tradfn als operand (zie voorgaande items: een tradfn moet benoemd worden; een tradfn wordt benoemd door embedding ...).
- Namen die in een dfn zijn toegewezen , zijn standaard lokaal ; namen toegewezen in een tradfn zijn globaal, tenzij gespecificeerd in een lokale lijst.
- Locals in een dfn hebben een lexicale scope ; locals in een tradfn hebben een dynamisch bereik , zichtbaar in aangeroepen functies, tenzij overschaduwd door hun lokale lijst.
- De argumenten van een dfn worden genoemd
⍺en⍵en de operanden van een dop worden genoemd⍺⍺en⍵⍵; de argumenten en operanden van een tradfn kunnen elke naam hebben, gespecificeerd op de leidende regel. - Het resultaat (indien aanwezig) van een dfn is naamloos; het resultaat (indien aanwezig) van een tradfn wordt genoemd in de kop.
- Een standaardwaarde voor ⍺ is netter gespecificeerd dan voor het linkerargument van een tradfn.
-
Recursie in een dfn wordt bewerkstelligd door het aanroepen van
∇of∇∇of zijn naam; recursie in een tradfn wordt bewerkstelligd door de naam ervan aan te roepen. -
Flow control in een dfn wordt bewerkstelligd door bewakers en functieaanroepen; dat in een tradfn is door controlestructuren en
→(goto) en lijnlabels . - Het evalueren van een uitdrukking in een dfn die niet eindigt op toewijzing, veroorzaakt terugkeer van de dfn; het evalueren van een regel in een tradfn die niet eindigt op toewijzing of goto geeft het resultaat van de regel weer.
- Een dfn keert terug bij het evalueren van een uitdrukking die niet eindigt op een toewijzing, bij het evalueren van een bewaakte uitdrukking, of na de laatste uitdrukking; een tradfn keert terug op
→(goto) regel 0 of een niet-bestaande regel, of bij evaluatie van een controlestructuur, of na de laatste regel.:Return - De eenvoudigere stroomregeling in een dfn maakt het gemakkelijker om staartrecursie te detecteren en te implementeren dan in een tradfn.
- Een dfn kan een tradfn aanroepen en vice versa ; een dfn kan worden gedefinieerd in een tradfn, en vice versa .
Geschiedenis
Kenneth E. Iverson , de uitvinder van APL, was ontevreden over de manier waarop gebruikersfuncties (tradfns) werden gedefinieerd. In 1974 bedacht hij "formele functiedefinitie" of "directe definitie" voor gebruik in expositie. Een directe definitie bestaat uit twee of vier delen, gescheiden door dubbele punten:
name : expression
name : expression0 : proposition : expression1
Geeft binnen een directe definitie ⍺het linkerargument en ⍵het rechterargument aan. In eerste instantie is het resultaat van expressionhet resultaat van de functie; in het tweede geval is het resultaat van de functie dat van expression0if propositionevalueert naar 0, of expression1als het evalueert naar 1. Toewijzingen binnen een directe definitie zijn dynamisch lokaal . Voorbeelden van het gebruik van directe definitie zijn te vinden in de Turing Award- lezing van 1979 en in boeken en sollicitatiebrieven.
Directe definitie was te beperkt voor gebruik in grotere systemen. De ideeën werden verder ontwikkeld door meerdere auteurs in meerdere werken, maar de resultaten waren onpraktisch. Hiervan kwam de "alternatieve APL-functiedefinitie" van Bunda in 1987 het dichtst in de buurt van de huidige faciliteiten, maar is gebrekkig in conflict met bestaande symbolen en in foutafhandeling die praktische problemen zou hebben veroorzaakt, en werd nooit geïmplementeerd. De belangrijkste distillaten van de verschillende voorstellen waren dat (a) de functie die wordt gedefinieerd anoniem is, waarbij de latere naamgeving (indien nodig) door middel van toewijzing wordt uitgevoerd; (b) de functie wordt aangeduid met een symbool en maakt daardoor anonieme recursie mogelijk .
In 1996 vond John Scholes van Dyalog Limited directe functies (dfns) uit. De ideeën ontstonden in 1989 toen hij een speciale uitgave van The Computer Journal las over functioneel programmeren. Hij ging toen verder met het bestuderen van functioneel programmeren en raakte sterk gemotiveerd ("ziek van verlangen", zoals Yeats ) om deze ideeën naar APL te brengen. Aanvankelijk opereerde hij onopvallend omdat hij bang was dat de veranderingen te radicaal en een onnodige complicatie van de taal zouden zijn; andere waarnemers zeggen dat hij heimelijk opereerde omdat Dyalog-collega's niet zo gecharmeerd waren en dachten dat hij zijn tijd aan het verspillen was en problemen voor mensen veroorzaakte. Dfns werden voor het eerst gepresenteerd in het Dyalog Vendor Forum op de APL '96 Conference en begin 1997 uitgebracht in Dyalog APL. Acceptatie en erkenning kwamen langzaam op gang. Nog in 2008, in Dyalog op 25 , een publicatie ter gelegenheid van het 25-jarig jubileum van Dyalog Limited, werden dfns nauwelijks genoemd (twee keer genoemd als "dynamische functies" en zonder uitwerking). Vanaf 2019 zijn dfns geïmplementeerd in Dyalog APL, NARS2000 en ngn/apl. Ze spelen ook een sleutelrol bij pogingen om de computercapaciteiten van een grafische verwerkingseenheid (GPU) te benutten .
Referenties
Externe links
- Officiële website , Dyalog