Funkcja bezpośrednia
Funkcja bezpośrednia ( dfn , wymawiana jako „dee fun”) to alternatywny sposób definiowania funkcji i operatora ( funkcja wyższego rzędu ) w języku programowania APL . Bezpośredni operator można również nazwać dopem (wymawiane „dee op”). Zostały wynalezione przez Johna Scholesa w 1996 roku. Stanowią unikalną kombinację programowania tablicowego , funkcji wyższego rzędu i programowania funkcjonalnego i są głównym wyróżnikiem APL z początku XXI wieku w porównaniu z poprzednimi wersjami.
dfn to sekwencja potencjalnie strzeżonych wyrażeń (lub tylko strażnika) między {
i }
, oddzielonych ⋄
lub nowymi wierszami, gdzie ⍺
oznacza lewy argument i ⍵
prawy, a ∇
oznacza rekurencję (odniesienie funkcji do siebie). Na przykład funkcja PT
sprawdza, czy każdy wiersz ⍵
jest trójką Pitagorasa (sprawdzając, czy suma kwadratów jest równa dwukrotności kwadratu maksimum).
0 0 0 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 1 1
Silnia jako dfn :
0
fakt ← { = ⍵: 1 ⋄ ⍵ × ∇ ⍵ - 1 } fakt 5 120 fakt ¨ ⍳ 10 ⍝ fakt zastosowany do każdego elementu od 0 do 9 1 1 2 6 24 120 720 5040 40320 362880
Opis
Zasady dla dfns są podsumowane przez następującą „kartę referencyjną”:
{ ⍺ funkcja ⍵ }
|
{ ⍺⍺ operator ⍵⍵ }
|
: strażnik |
⍺ lewy argument |
⍺⍺ lewy operand |
:: ochrona przed błędami |
⍵ właściwy argument |
⍵⍵ prawy operand |
⍺ ← domyślny lewy argument |
∇ samoodniesienie |
∇∇ samoodniesienie |
s ← nieśmiały wynik |
dfn to sekwencja potencjalnie strzeżonych wyrażeń (lub tylko strażnika) między {
i }
, oddzielonych ⋄
lub znakami nowej linii.
strażnik ekspresji : strażnik ekspresji :
Wyrażenia i/lub osłony są oceniane po kolei. Strażnik musi ocenić na 0 lub 1; skojarzone z nim wyrażenie jest oceniane, jeśli wartość wynosi 1. Funkcja dfn kończy się po pierwszym niestrzeżonym wyrażeniu, które nie kończy się na przypisaniu , lub po pierwszym strzeżonym wyrażeniu, którego wartość straży wynosi 1, lub jeśli nie ma więcej wyrażeń. Wynik dfn jest wynikiem ostatniego ocenianego wyrażenia. Jeśli to ostatnie oceniane wyrażenie kończy się przypisaniem, wynikiem jest „nieśmiałość” — nie jest on automatycznie wyświetlany w sesji.
Nazwy przypisane w dfn są domyślnie lokalne , z zakresem leksykalnym .
⍺
oznacza lewy argument funkcji, a ⍵
prawy; ⍺⍺
oznacza lewy operand, a ⍵⍵
prawy. Jeżeli ⍵⍵
, to dfn jest operatorem diadicznym ; jeśli występuje tylko ⍺⍺ , ale nie
⍵⍵
, to jest to operator monadyczny; jeśli nie ⍺⍺
, ani ⍵⍵
, to dfn jest funkcją.
Specjalna składnia wyrażenia ⍺ ←
jest używana do nadania wartości domyślnej lewemu argumentowi, jeśli dfn jest wywoływana monadycznie, to znaczy wywoływana bez lewego argumentu. . ← Wyrażenie
⍺ nie jest oceniane inaczej
∇
oznacza rekurencję lub samoodniesienie przez funkcję, a ∇∇
oznacza samoodniesienie przez operatora. Takie oznaczenie pozwala na anonimową rekurencję .
Wychwytywanie błędów jest zapewniane przez strażników błędów, errnums :: expression
. Gdy generowany jest błąd, system dynamicznie przeszukuje wywoływane funkcje w poszukiwaniu zabezpieczenia przed błędami, które pasuje do błędu. Jeśli zostanie znaleziony, środowisko wykonawcze jest przywracane do stanu bezpośrednio przed wykonaniem funkcji ochrony przed błędami, a powiązane wyrażenie ochrony przed błędami jest oceniane jako wynik dfn.
Dodatkowe opisy, wyjaśnienia i samouczki dotyczące dfns są dostępne w cytowanych artykułach.
Przykłady
Przykłady tutaj ilustrują różne aspekty dfns. Dodatkowe przykłady można znaleźć w cytowanych artykułach.
Domyślny lewy argument
Funkcja { ⍺ + 0j1 × ⍵ }
dodaje ⍺
do 0j1
( ja lub ) razy ⍵
.
0
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 0J1 0J2 1J ¯2 1J¯1 1 1J1 1J2 2J¯2 2J¯1 2 2J1 2J2
Znaczenie tej funkcji można zobaczyć w następujący sposób:
Liczby zespolone można konstruować jako uporządkowane pary liczb rzeczywistych, podobnie jak liczby całkowite można konstruować jako uporządkowane pary liczb naturalnych, a liczby wymierne jako uporządkowane pary liczb całkowitych. Dla liczb zespolonych
{ ⍺ + 0j1 × ⍵ }
pełni taką samą rolę jak-
dla liczb całkowitych i÷
dla liczb wymiernych.
Ponadto, analogicznie do monadycznej - ⍵
⇔ 0 - ⍵
( negate ) i monadycznej ÷ ⍵
⇔ 1 ÷ ⍵
( reciprocal ), przydatna jest monadyczna definicja funkcji, realizowana poprzez podanie domyślnej wartości 0 dla ⍺
: if 0 j ← { ⍺ ← ⋄ ⍺ + 0j1 × ⍵ }
, potem j ⍵
⇔ 0 jot ⍵
⇔ 0 + 0j1 × ⍵
.
0
0 0
j ← { ⍺ ← ⋄ ⍺ + 0j1 × ⍵ } 3 jot 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 ∘ ○ sałata ← 2 ∘ ○ Eulera ← { ( * j ⍵ ) = ( sałata ⍵ ) j ( grzech ⍵ ) } Eulera ( ¯ 0,5 +? 10 ⍴ ) j ( ¯ 0,5 +? 10 ⍴ ) 1 1 1 1 1 1 1 1 1 1
Ostatnie wyrażenie ilustruje wzór Eulera na dziesięciu liczbach losowych z częściami rzeczywistymi i urojonymi w przedziale .
Pojedyncza rekurencja
Trójskładnikowa konstrukcja zbioru Cantora zaczyna się od przedziału [0,1] i na każdym etapie usuwa środkową tercję z każdego pozostałego podprzedziału:
Zbiór Cantora rzędu ⍵
określony jako dfn:
0 0
0
0
0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Kantor ← { = ⍵: , 1 ⋄ , 1 1 ∘. ∧ ∇ ⍵ - 1 } Kantor 1 Kantor 1 1 1 Kantor 2 1 1 1 1 Kantor 3 1 1 1 1 1 1 1 1
Cantor 0 do Cantor 6 przedstawiony jako czarne paski:
Funkcja sito ⍵
oblicza wektor bitowy o długości ⍵
tak, że bit i
(dla 0 ≤ i
oraz i < ⍵
) wynosi 1 wtedy i tylko wtedy, gdy i
jest liczbą pierwszą .
0 0
0
0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0
0 sito ← { 4 ≥ ⍵:⍵ ⍴ 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 ← @ 1 ⊃ { ( m ⍴ ⍵ ) > m ⍴ ⍺ ↑ 1 ⊣ m ← n ⌊ ⍺ ×≢ ⍵ } ⌿ ⊖ 1 , p { r < q ← b ⍳ 1 : b ⊣ b [ ⍵ ] ← 1 ⋄ b [ q , q ×⍸ b ↑ ⍨ ⌈ n ÷ q ] ← ⋄ ∇ ⍵ , q } p } 10 10 ⍴ sito 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 b ← sito 1e9 ≢ b 1000000000 ( 10 *⍳ 10 ) ( + ⌿ ↑ ) ⍤ 1 ⊢ b 4 25 168 1229 9592 78498 664579 5761455 5084 7534
Ostatnia sekwencja, liczba liczb pierwszych mniejsza niż potęga 10, jest początkowym segmentem OEIS : A006880 . Ostatnia liczba, 50847534, to liczba liczb pierwszych mniejsza niż . Nazywa się to liczbą Bertelsena, pamiętnie opisaną przez MathWorld jako „błędna nazwa, której błędnie podano błędną wartość ".
sito
używa dwóch różnych metod do oznaczania kompozytów zerami, obie realizowane przy użyciu lokalnych anonimowych dfns: Pierwsza wykorzystuje sito Eratostenesa na początkowej masce 1 i przedrostek liczb pierwszych 2 3...43, używając operatora wstawiania ⌿
( prawe zagięcie ). (Długość przedrostka uzyskuje się przez porównanie z pierwotną funkcją × ⍀ p
.) Drugi znajduje najmniejszą nową liczbę pierwszą q
pozostałą w b
( q ← b ⍳ 1
) i ustawia na 0 sam bit q
i bity w q
razy liczby na pozostałych 1 bitach w początkowym segmencie b
( ⍸ b ↑ ⍨ ⌈ n ÷ q
). Ten drugi dfn używa rekurencji ogona.
Rekurencja ogona
Zazwyczaj funkcja silni jest definiowana rekurencyjnie (jak powyżej ), ale można ją zakodować tak, aby wykorzystywała rekurencję ogona , używając lewego argumentu akumulatora:
0 fac ← { ⍺ ← 1 ⋄ ⍵ = : ⍺ ⋄ ( ⍺ × ⍵ ) ∇ ⍵ - 1 }
Podobnie wyznacznik kwadratowej macierzy zespolonej za pomocą eliminacji Gaussa można obliczyć za pomocą rekurencji ogonowej:
0
det ← { ⍝ wyznacznik kwadratowej macierzy zespolonej ⍺ ← 1 ⍝ iloczyn dotychczasowych współczynników kofaktorów =≢ ⍵:⍺ ⍝ wynik dla 0 na 0 ( i j ) ← ( ⍴ ⍵ ) ⊤⊃⍒|, ⍵ ⍝ indeks wiersza i kolumny elementu maksymalnego k ← ⍳≢ ⍵ ( ⍺ × ⍵ [ i ; j ] × ¯1 * i + j ) ∇ ⍵ [ k ~ i ; k ~ jot ] - ⍵ [ k ~ ja ; j ] ∘. × ⍵ [ ja ; k ~ jot ] ÷ ⍵ [ ja ; j ] }
Wielokrotna rekurencja
Podział nieujemnej liczby = + ⌿ v wektorem
dodatnich całkowitych takich, że n gdzie kolejność w jest znacząca Na przykład 2 2
i 2 1 1
to partycje 4, a 2 1 1
i 1 2 1
i 1 1 2
są uważane za tę samą partycję.
Funkcja partycji zlicza liczbę partycji. Funkcja jest przedmiotem zainteresowania teorii liczb , badanej przez Eulera , Hardy'ego , Ramanujana , Erdősa i innych. Relacja powtarzalności
twierdzenia o liczbach pięciokątnych Eulera . Zapisane jako dfn:
0
pn ← { 1 ≥ ⍵: ≤ ⍵ ⋄ - ⌿ + ⌿ ∇ ¨ 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
Krok bazowy 0 1 ≥ ⍵: ≤ ⍵
stwierdza, że dla 1 ≥ ⍵
wynikiem funkcji jest 0 ≤ ⍵
, 1 jeśli ⍵ wynosi 0 lub 1 i 0 w przeciwnym razie. Krok rekurencyjny jest wysoce wielokrotnie rekurencyjny. Na przykład pn 200
spowodowałoby zastosowanie funkcji do każdego elementu rec 200
, którym są:
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
a pn 200 wymaga
niż wszechświata do obliczenia ( funkcji do siebie) Czas obliczeń można skrócić przez zapamiętywanie , tutaj zaimplementowane jako operator bezpośredni (funkcja wyższego rzędu) M
:
0
M ← { fa ← ⍺⍺ ja ← 2 + '⋄' ⍳ ⍨ t ← 2 ↓, ⎕cr 'f' ⍎ '{T←(1+⍵)⍴¯1 ⋄' , ( ja ↑ t ) , '¯ 1≢T[⍵]:⊃T[⍵] ⋄ ⊃T[⍵]←⊂' , ( i ↓ t ) , '⍵}⍵' } pn M 200 3.973E12 ⍕ pn M 200 ⍝ sformatuj do 0 miejsc po przecinku 3972999029388
Ta wartość pn M 200
zgadza się z wartością obliczoną przez Hardy'ego i Ramanujana w 1918 roku.
Operator memo M
definiuje wariant swojego argumentu funkcji ⍺⍺
, aby użyć pamięci podręcznej T
, a następnie ocenia go. Z operandem pn
wariant to:
0 { T ← ( 1 + ⍵ ) ⍴ ¯1 ⋄ { 1 ≥ ⍵: ≤ ⍵ ⋄ ¯1 ≢ T [ ⍵ ] : ⊃ T [ ⍵ ] ⋄ ⊃ T [ ⍵ ] ← ⊂- ⌿ + ⌿ ∇ ¨ rec ⍵ } ⍵ }
Bezpośredni operator (dop)
Szybkie sortowanie na tablicy ⍵
działa na zasadzie losowego wybierania „oś obrotu” spośród jej głównych komórek, a następnie łączenia posortowanych komórek głównych, które ściśle poprzedzają oś obrotu, głównych komórek równych osi obrotu i posortowanych komórek głównych, które ściśle podążają za osią obrotu, jak określono za pomocą funkcji porównania ⍺⍺
. Zdefiniowany jako operator bezpośredni (dop) Q
:
00 0
0
0
0 Q ← { 1 ≥≢ ⍵:⍵ ⋄ ( ∇ ⍵ ⌿⍨ > s ) ⍪ ( ⍵ ⌿⍨ = s ) ⍪ ∇ ⍵ ⌿⍨ < s ← ⍵ ⍺⍺ ⍵ ⌷ ⍨ ?≢ ⍵ } ⍝ poprzedza ⍝ następuje ⍝ równa się 2 ( ×- ) 8 8 ( ×- ) 2 8 ( ×- ) 8 ¯1 1 x ← 2 19 3 8 3 6 9 4 19 7 10 15 14 ( ×- ) Q x 2 3 3 4 6 7 8 9 10 14 15 19 19
Q3
jest wariantem, który łączy trzy części objęte funkcją ⊂
zamiast części per se . Trzy części generowane w każdym kroku rekurencyjnym są widoczne w strukturze wyniku końcowego. Wielokrotne zastosowanie funkcji wyprowadzonej z Q3 do tego samego argumentu daje różne wyniki, ponieważ punkty obrotu są wybierane losowo. Przechodzenie
wyników w kolejności daje tę samą posortowaną tablicę.
00 0
0
0
Q3 ← { 1 ≥≢ ⍵:⍵ ⋄ ( ⊂ ∇ ⍵ ⌿⍨ > s ) ⍪ ( ⊂ ⍵ ⌿⍨ = s ) ⍪⊂ ∇ ⍵ ⌿⍨ < s ← ⍵ ⍺⍺ ⍵ ⌷ ⍨ ?≢ ⍵ } ( ×- ) Q3 x ┌───────────────────────────────────── ───────┬─ ────┬┐ │┌──────────────┬─┬─────────────── ────────── ┐│ 19 19 ││ ││┌──────┬───┬─┐│ 6 │┌──────┬─┬──── ──────────┐ ││ ││ │││┌┬─┬─┐│ 3 3 │ 4 ││ ││┌┬─┬─┐│ 9 │┌┬──┬─── ─────┐│││ ││ │││││ │ 2 ││ │ ││ ││││ 7 │ 8 ││ │││ 10 │┌──┬──┬┐││││ ││ │││└┴─┴─┘│ │ ││ ││└┴─┴─┘│ │││ ││ 14 │ 15 ││││││ ││ ││└────── ┴───┴─┘│ ││ │ ││ │ │└──┴──┴┘││││ ││ ││ │ ││ │ │└┴──┴────────┘│ ││ ││ ││ │ │└─── ───┴─┴──────────────┘││ ││ │└──────────── ──┴─┴────── ───────────────────┘│ ││ └─────────────── ─────────── ──────────────────┴─────┴┘ ( ×- ) Q3 x ┌────────── ─────── ──────────┬─┬─────────────────────────── ──┐ │┌┬─┬── ────────────────────┐│ 7 │┌─────────────── ─────┬──── ─┬┐│ │││ │┌┬─┬─────────────────┐││ ││┌──── ──┬──┬───── ───┐│ 19 19 │││ │││ │││ 2 │┌────────────┬─┬┐│││ │ ││┌┬─┬─┐│ 10 │ ┌──┬──┬┐││ │││ │││ │││ ││┌───────┬─┬┐│ 6 ││││ │ │││││ 8 │ 9 ││ ││ 14 │ 15 ││││ │││ │││ │││ │││┌┬───┬┐│ 4 │││ │││││ │││└┴─┴─┘│ │└ ──┴──┴┘││ │││ │││ │││ │││││ 3 3 │││ │││ │││││ ││ └──────┴──┴─ ───────┘│ │││ │││ │││ │││└┴───┴┘│ │││ │││││ │ └─────────── ─────────┴─────┴┘│ │││ │││ ││└───────┴─┴┘│ │││││ │ │ │││ │ ││ │└────────────┴─┴┘│││ │ │ │││ │└┴─┴───── ──────────── ┘││ │ │ │└┴─┴──────────────────────┘│ │ │ └─ ──────────── ──────────────┴─┴─────────────────────── ──────┘
Powyższe sformułowanie nie jest nowe; patrz na przykład rysunek 3.7 klasycznej książki The Design and Analysis of Computer Algorithms . Jednak w przeciwieństwie do pidgin ALGOL z rysunku 3.7, Q
jest wykonywalny, a kolejność częściowa używana w sortowaniu jest operandem, ( ×- )
w powyższych przykładach.
Dfns z operatorami i pociągami
Dfns, zwłaszcza anonimowe dfns, dobrze współpracują z operatorami i pociągami. Poniższy fragment rozwiązuje zagadkę „Pereł programowania”: biorąc pod uwagę słownik angielskich słów, tutaj przedstawiony jako macierz znaków a
, znajdź wszystkie zestawy anagramów.
za { ⍵ [ ⍋ ⍵ ] } ⍤ 1 ⊢ za ( { ⍵ [ ⍋ ⍵ ] } ⍤ 1 { ⊂ ⍵ } ⌸ ⊢ ) a poklepuje ┌────┬────┬── ──┐ splunął apst │ klepie │ herbaty │ gwiazda │ herbaty aest │ splunąć │ nasycić │ │ nasycić aest │ taps │ etas │ │ taps apst │ przeszłość │ siedzenie │ │ etas aest │ │ zjada │ │ przeszłość apst │ │ tase │ │ siedzenie aest │ │ wschód │ │ zjada aest │ │ seta │ │ tase aest └────┴────┴────┘ star arst wschód aest seta aest
Algorytm działa na zasadzie sortowania wierszy indywidualnie ( { ⍵ [ ⍋ ⍵ ] } ⍤ 1 ⊢ a
), a te posortowane wiersze są używane jako klucze („podpis” w opisie Pereł Programowania) do głównego operatora ⌸
do grupowania wierszy macierz. Wyrażenie po prawej stronie to pociąg , forma składniowa stosowana przez APL do programowania cichego . Tutaj jest to izolowana sekwencja trzech funkcji taka, że ( f g h ) ⍵
⇔ ( f ⍵ ) g ( h ⍵ )
, skąd wyrażenie po prawej stronie jest równoważne ( { ⍵ [ ⍋ ⍵ ] } ⍤ 1 ⊢ a ) { ⊂ ⍵ } ⌸ za
.
Zakres leksykalny
Kiedy wewnętrzny (zagnieżdżony) dfn odnosi się do nazwy, szuka się go, patrząc na zewnątrz przez otaczające dfns, a nie w dół stosu wywołań . Mówi się, że ten system wykorzystuje zakres leksykalny zamiast zwykłego zakresu dynamicznego APL . Rozróżnienie staje się widoczne dopiero wtedy, gdy wywołana zostanie funkcja zdefiniowana na poziomie zewnętrznym. W przypadku bardziej typowych wezwań przychodzących te dwa systemy są nie do odróżnienia.
Na przykład w następującej funkcji who
zmienna ty
jest zdefiniowana zarówno w samej what
, jak iw funkcji wewnętrznej f1
. Kiedy f1
wywołuje na zewnątrz f2
i f2
odnosi się do ty
, znajduje zewnętrzny (o wartości 'lexical'
) zamiast tego zdefiniowanego w f1
(o wartości 'dynamic'
):
który ← { ty ← 'leksykalny' f1 ← { ty ← 'dynamiczny' ⋄ f2 ⍵ } f2 ← { ty , ⍵ } f1 ⍵ } który 'zakres' zakres leksykalny
Ochrona przed błędami
Poniższa funkcja ilustruje użycie strażników błędów:
0
plus ← { tx ← „złapać wszystko” ⋄ :: tx tx ← „dziedzina” ⋄ 11 :: tx tx ← „długość” ⋄ 5 :: tx ⍺ + ⍵ } 2 plus 3 ⍝ brak błędów 5 2 3 4 5 plus ' trzy' ⍝ długości argumentów nie pasują do długości 2 3 4 5 plus 'cztery' ⍝ nie można dodać znaków dziedzina 2 3 plus 3 4 ⍴ 5 ⍝ nie można dodać wektora do macierzy catch all
W APL błąd numer 5 to „błąd długości”; numer błędu 11 to „błąd domeny”; a numer błędu 0 to „catch all” dla numerów błędów od 1 do 999.
Przykład pokazuje odwijanie środowiska lokalnego przed obliczeniem wyrażenia strażnika błędów. Lokalna nazwa tx
jest ustawiona tak, aby opisywać zakres następującej po niej ochrony przed błędami. Gdy wystąpi błąd, środowisko jest rozwijane, aby odsłonić poprawną statycznie wartość tx .
Dfns kontra tradfns
Ponieważ funkcje bezpośrednie to dfns, funkcje APL zdefiniowane w tradycyjny sposób są określane jako tradfns, wymawiane jako „trad funs”. Tutaj dfns i tradfns są porównywane przez uwzględnienie funkcji sito
: Po lewej stronie jest dfn (jak zdefiniowano powyżej ); pośrodku znajduje się tradfn używający struktur kontrolnych ; po prawej jest tradfn używający gotos ( →
) i etykiet linii .
0 0
0
0
sito ← { 4 ≥ ⍵:⍵ ⍴ 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 ← @ 1 ⊃ { ( m ⍴ ⍵ ) > m ⍴ ⍺ ↑ 1 ⊣ m ← n ⌊ ⍺ ×≢ ⍵ } ⌿ ⊖ 1 , p { r < q ← b ⍳ 1 : b ⊣ b [ ⍵ ] ← 1 ⋄ b [ q , q × ⍸ b ↑ ⍨ ⌈ n ÷ q ] ← ⋄ ∇ ⍵ , q } p }
|
0 0
0
0
∇ b ← sito1 n ; ja ; m ; p ; q ; r : Jeśli 4 ≥ n ⋄ b ← n ⍴ 1 1 ⋄ : Powrót ⋄ : Koniec Jeśli 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 : Dla q : In p ⋄ b ← ( m ⍴ b ) > m ⍴ q ↑ 1 ⊣ m ← n ⌊ q ×≢ b ⋄ : EndFor b [ 1 ] ← : Podczas gdy r ≥ q ← b ⍳ 1 ⋄ b [ q , q × ⍸ b ↑ ⍨ ⌈ n ÷ q ] ← ⋄ p ⍪ ← q ⋄ : EndWhile b [ p ] ← 1 ∇
|
0 0 0
0
0
0
∇ b ← sito2 n ; ja ; m ; p ; q ; r → L10 ⍴ ⍨ 4 < n ⋄ b ← n ⍴ 1 1 ⋄ → 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 ja ← ⋄ b ← 1 L20 : b ← ( m ⍴ b ) > m ⍴ p [ ja ] ↑ 1 ⊣ m ← n ⌊ p [ ja ] ×≢ b → L20 ⍴ ⍨ ( ≢ p ) > ja ← 1 + ja b [ 1 ] ← L30 : → L40 ⍴ ⍨ r < q ← b ⍳ 1 ⋄ b [ q , q × ⍸ b ↑ ⍨ ⌈ n ÷ q ] ← ⋄ p ⍪ ← q ⋄ → L30 L40 : b [ p ] ← 1 ∇
|
- Dfn może być anonimowy ; tradfn musi mieć nazwę.
- dfn jest nazywany przez przypisanie (
←
); tradfn jest nazywany przez osadzenie nazwy w reprezentacji funkcji i zastosowanie⎕fx
(funkcja systemowa) do tej reprezentacji. - dfn jest wygodniejszy niż tradfn jako operand (patrz poprzednie punkty: tradfn musi mieć nazwę; tradfn jest nazywany przez osadzanie ...).
- Nazwy przypisane w dfn są domyślnie lokalne ; nazwy przypisane w tradfn są globalne , chyba że określono je na liście locals.
- Lokalne w dfn mają zakres leksykalny ; locals w tradfn mają dynamiczny zasięg , widoczny w wywoływanych funkcjach, chyba że jest to cień ich listy locals.
- Argumenty dfn są nazwane
⍺
i⍵
, a operandy dop są nazwane⍺⍺
i⍵⍵
; argumenty i operandy tradfn mogą mieć dowolną nazwę, określoną w jej wiodącym wierszu. - Wynik (jeśli istnieje) dfn jest nienazwany; wynik (jeśli istnieje) tradfn jest nazwany w jego nagłówku.
- Wartość domyślna dla ⍺ jest określona dokładniej niż dla lewego argumentu tradfn.
-
Rekurencja w dfn odbywa się poprzez wywołanie
∇
lub∇∇
lub jego nazwy; rekurencja w tradfn odbywa się poprzez wywołanie jego nazwy. -
Kontrola przepływu w dfn jest realizowana przez strażników i wywołania funkcji; to w tradfn jest przez struktury kontrolne i
→
(goto) i etykiety linii. - Ocena wyrażenia w dfn, które nie kończy się przypisaniem, powoduje powrót z dfn; ocena linii w tradfn nie kończącej się przypisaniem lub goto wyświetla wynik linii.
- Funkcja dfn zwraca przy ocenie wyrażenia, które nie kończy się przypisaniem, przy ocenie wyrażenia chronionego lub po ostatnim wyrażeniu; tradfn powraca w
→
(goto) 0 lub w nieistniejącej linii, lub po ocenie struktury kontrolnej: Return
lub po ostatniej linii. - Prostsza kontrola przepływu w dfn ułatwia wykrywanie i wdrażanie rekurencji ogona niż w tradfn.
- dfn może wywoływać tradfn i vice versa ; dfn może być zdefiniowany w tradfn i vice versa .
Historia
Kenneth E. Iverson , wynalazca APL, był niezadowolony ze sposobu definiowania funkcji użytkownika (tradfns). W 1974 roku opracował „formalną definicję funkcji” lub „definicję bezpośrednią” do wykorzystania w ekspozycji. Definicja bezpośrednia składa się z dwóch lub czterech części oddzielonych dwukropkami:
nazwa : nazwa wyrażenia : wyrażenie0 : propozycja : wyrażenie1
W bezpośredniej definicji ⍺
oznacza lewy argument, a ⍵
prawy argument. W pierwszym przypadku wynik wyrażenia jest
wynikiem funkcji; w drugim przypadku wynikiem funkcji jest wyrażenie0 ,
jeśli zdanie
ma wartość 0, lub wyrażenie1
, jeśli ma wartość 1. Przypisania w ramach definicji bezpośredniej są dynamicznie lokalne . Przykłady użycia bezpośredniej definicji można znaleźć w Turing Award z 1979 r . oraz w książkach i dokumentach aplikacyjnych.
Definicja bezpośrednia była zbyt ograniczona do użytku w większych systemach. Pomysły były dalej rozwijane przez wielu autorów w wielu pracach, ale wyniki były nieporęczne. Spośród nich „alternatywna definicja funkcji APL” Bundy z 1987 r. Była najbliższa obecnym obiektom, ale zawiera błędy w konfliktach z istniejącymi symbolami i obsługą błędów, które spowodowałyby praktyczne trudności, i nigdy nie została wdrożona. Główne destylaty z różnych propozycji były takie, że (a) definiowana funkcja jest anonimowa, a późniejsze nazewnictwo (jeśli jest wymagane) jest dokonywane przez przypisanie; (b) funkcja jest oznaczona symbolem, a tym samym umożliwia anonimową rekurencję .
W 1996 roku John Scholes z Dyalog Limited wynalazł funkcje bezpośrednie (dfns). Pomysły zrodziły się w 1989 roku, kiedy przeczytał specjalne wydanie The Computer Journal na temat programowania funkcjonalnego. Następnie zaczął studiować programowanie funkcjonalne i był silnie zmotywowany („chory z pragnienia”, jak Yeats ), aby wprowadzić te pomysły do APL. Początkowo działał ukradkiem, ponieważ obawiał się, że zmiany mogą zostać uznane za zbyt radykalne i niepotrzebne skomplikowanie języka; inni obserwatorzy twierdzą, że działał ukradkiem, ponieważ koledzy Dyalog nie byli tak zachwyceni i myśleli, że marnuje czas i sprawia ludziom kłopoty. Dfns zostały po raz pierwszy zaprezentowane na Dyalog Vendor Forum na konferencji APL '96 i wydane w Dyalog APL na początku 1997 roku. Akceptacja i uznanie nadchodziły powoli. Jeszcze w 2008 roku, w Dyalog w 25 , publikacji z okazji 25-lecia Dyalog Limited, prawie nie wspomniano o dfns (wspomniano dwukrotnie jako „funkcje dynamiczne” i bez rozwinięcia). Od 2019 r. dfns są implementowane w Dyalog APL, NARS2000 i ngn/apl. Odgrywają również kluczową rolę w wysiłkach zmierzających do wykorzystania możliwości obliczeniowych procesora graficznego (GPU).
Linki zewnętrzne
- Oficjalna strona internetowa , Dialog