Função direta - Direct function
Uma função direta ( dfn , pronuncia-se "dee fun") é uma forma alternativa de definir uma função e um operador (uma função de ordem superior ) na linguagem de programação APL . Um operador direto também pode ser chamado de dop (pronuncia-se "dee op"). Eles foram inventados por John Scholes em 1996. Eles são uma combinação única de programação de array , função de ordem superior e programação funcional , e são um grande avanço distintivo do APL do início do século 21 em relação às versões anteriores.
Um dfn é uma sequência de expressões possivelmente protegidas (ou apenas uma guarda) entre {e }, separadas por ⋄ou novas linhas, em que ⍺denota o argumento esquerdo e ⍵o direito, e ∇denota recursão (auto-referência de função). Por exemplo, a função PTtesta se cada linha de ⍵é um trio pitagórico (testando se a soma dos quadrados é igual a duas vezes o quadrado do máximo).
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
A função fatorial como um 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
Descrição
As regras para dfns são resumidas pelo seguinte "cartão de referência":
{⍺ function ⍵}
|
{⍺⍺ operator ⍵⍵}
|
: guarda
|
⍺ argumento esquerdo
|
⍺⍺ operando esquerdo
|
:: guarda de erros
|
⍵ argumento certo
|
⍵⍵ operando certo
|
⍺← argumento esquerdo padrão
|
∇ auto-referência
|
∇∇ auto-referência
|
s← resultado tímido
|
Um dfn é uma sequência de expressões possivelmente protegidas (ou apenas uma proteção) entre {e }, separadas por ⋄ou novas linhas.
expression
guard: expression
guard:
As expressões e / ou protetores são avaliados em sequência. Um guarda deve ser avaliado como 0 ou 1; sua expressão associada é avaliada se o valor for 1. Um dfn termina após a primeira expressão desprotegida que não termina na atribuição , ou após a primeira expressão protegida cujo guarda é avaliado como 1, ou se não houver mais expressões. O resultado de um dfn é o da última expressão avaliada. Se a última expressão avaliada terminar em atribuição, o resultado será "tímido" - não exibido automaticamente na sessão.
Os nomes atribuídos em um dfn são locais por padrão, com escopo léxico .
⍺denota o argumento da função à esquerda e ⍵à direita; ⍺⍺denota o operando esquerdo e ⍵⍵o direito. Se ⍵⍵ocorrer na definição, então o dfn é um operador diádico ; se apenas ⍺⍺ocorre, mas não ⍵⍵, então é um operador monádico; se nem ⍺⍺ou ⍵⍵ocorrer, então o dfn é uma função.
A sintaxe especial é usada para fornecer um valor padrão para o argumento esquerdo se um dfn for chamado monadicamente, ou seja, chamado sem nenhum argumento esquerdo. O não é avaliado de outra forma.
⍺←expression⍺←expression
∇denota recursão ou autorreferência pela função e ∇∇denota autorreferência pelo operador. Essa denotação permite a recursão anônima .
A interceptação de erros é fornecida por meio de proteções contra erros . Quando um erro é gerado, o sistema procura dinamicamente nas funções de chamada por um protetor de erro que corresponda ao erro. Se um for encontrado, o ambiente de execução é devolvido ao seu estado imediatamente anterior à execução da proteção contra erros e a expressão associada da proteção contra erros é avaliada como o resultado do dfn.
errnums::expression
Descrições, explicações e tutoriais adicionais sobre dfns estão disponíveis nos artigos citados.
Exemplos
Os exemplos aqui ilustram diferentes aspectos do dfns. Exemplos adicionais são encontrados nos artigos citados.
Argumento esquerdo padrão
A função adiciona a ( i ou √ -1 ) vezes .
{⍺+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
O significado desta função pode ser visto da seguinte forma:
Os números complexos podem ser construídos como pares ordenados de números reais, semelhante a como os inteiros podem ser construídos como pares ordenados de números naturais e os números racionais como pares ordenados de inteiros. Para números complexos, desempenha o mesmo papel que para inteiros e para números racionais.
{⍺+0j1×⍵}-÷
Além disso, análogo àquele ⇔ monádico ( negar ) e ⇔ monádico ( recíproco ), uma definição monádica da função é útil, efetuada especificando um valor padrão de 0 para : se , então ⇔ ⇔ .
-⍵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
A última expressão ilustra a fórmula de Euler em dez números aleatórios com partes reais e imaginárias no intervalo .
Recursão única
A construção ternária do conjunto Cantor começa com o intervalo [0,1] e em cada estágio remove o terço médio de cada subintervalo restante:
O conjunto de ordens Cantor ⍵definido como um 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 a Cantor 6 representado como barras pretas:
A função calcula um vetor de bits de comprimento de forma que o bit (para e ) seja 1 se e somente se for primo .
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
A última sequência, o número de primos menor que potências de 10, é um segmento inicial do OEIS : A006880 . O último número, 50847534, é o número de primos menor que . É chamado de número de Bertelsen, descrito de forma memorável por MathWorld como "um nome errado dado erroneamente o valor errado de ".
sieveusa dois métodos diferentes para marcar os compostos com 0s, ambos efetuados usando dfns anônimos locais: O primeiro usa a peneira de Eratóstenes em uma máscara inicial de 1 e um prefixo dos primos 2 3 ... 43, usando o operador de inserção⌿ ( dobra à direita ) (O comprimento do prefixo é obtido por comparação com a função primorial .) O segundo encontra o menor novo primo restante em ( ), e define o próprio bit 0 e bits às vezes os números em 1 bits restantes em um segmento inicial de ( ) . Este segundo dfn usa recursão de cauda.
×⍀pqbq←b⍳1qqb⍸b↑⍨⌈n÷q
Recursão de cauda
Normalmente, a função fatorial é definida recursivamente (como acima ), mas pode ser codificada para explorar a recursão da cauda usando um argumento acumulador esquerdo:
fac←{⍺←1 ⋄ ⍵=0:⍺ ⋄ (⍺×⍵) ∇ ⍵-1}
Da mesma forma, o determinante de uma matriz quadrada complexa usando eliminação de Gauss pode ser calculado com recursão de cauda:
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]
}
Recursão múltipla
Uma partição de um inteiro não negativo é um vetor de inteiros positivos de tal forma que , onde a ordem não é significativa. Por exemplo, e são partições de 4, e e e são consideradas a mesma partição.
n = +⌿v2 22 1 12 1 11 2 11 1 2
A função de partição conta o número de partições. A função é de interesse na teoria dos números , estudada por Euler , Hardy , Ramanujan , Erdős e outros. A relação de recorrência
derivado do teorema do número pentagonal de Euler . Escrito como 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
A etapa básica afirma que , para , o resultado da função é , 1 se ⍵ for 0 ou 1 e 0 caso contrário. A etapa recursiva é altamente multiplamente recursiva. Por exemplo, resultaria na aplicação da função a cada elemento de , que são:
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
e requer mais tempo do que a idade do universo para ser computado ( chamadas de função para si mesmo). O tempo de computação pode ser reduzido pela memoização , aqui implementada como o operador direto (função de ordem superior) :
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
Este valor de concorda com aquele calculado por Hardy e Ramanujan em 1918.
pn M 200
O operador memo Mdefine uma variante de sua função operando ⍺⍺para usar um cache T e a avalia. Com o operando, pna variante é:
{T←(1+⍵)⍴¯1 ⋄ {1≥⍵:0≤⍵ ⋄ ¯1≢T[⍵]:⊃T[⍵] ⋄ ⊃T[⍵]←⊂-⌿+⌿∇¨rec ⍵}⍵}
Operador direto (dop)
Quicksort em uma matriz ⍵funciona escolhendo um "pivô" aleatoriamente entre suas células principais, em seguida, catenando as células principais classificadas que precedem estritamente o pivô, as células principais iguais ao pivô e as células principais classificadas que seguem estritamente o pivô, como determinado por uma função de comparação ⍺⍺. Definido como um operador direto (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
Q3é uma variante que catena as três partes incluídas pela função, em ⊂vez das partes em si . As três partes geradas em cada etapa recursiva são aparentes na estrutura do resultado final. Aplicar a função derivada de Q3ao mesmo argumento várias vezes fornece resultados diferentes porque os pivôs são escolhidos aleatoriamente. A travessia ordenada dos resultados produz a mesma matriz classificada.
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│││ │││ │││││ ││└──────┴──┴────────┘│ │││
│││ │││ │││└┴───┴┘│ │││ │││││ │└────────────────────┴─────┴┘│
│││ │││ ││└───────┴─┴┘│ │││││ │ │
│││ │││ │└────────────┴─┴┘│││ │ │
│││ │└┴─┴─────────────────┘││ │ │
│└┴─┴──────────────────────┘│ │ │
└───────────────────────────┴─┴─────────────────────────────┘
A formulação acima não é nova; veja, por exemplo, a Figura 3.7 do clássico The Design and Analysis of Computer Algorithms . No entanto, ao contrário do programa ALGOL pidgin na Figura 3.7, é executável e a ordem parcial usada na classificação é um operando, conforme os exemplos acima.
Q(×-)
Dfns com operadoras e trens
Dfns, especialmente dfns anônimos, funcionam bem com operadoras e trens. O trecho a seguir resolve um quebra-cabeça "Pérolas de programação": dado um dicionário de palavras em inglês, aqui representado como a matriz de caracteres a, encontre todos os conjuntos de anagramas.
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
O algoritmo funciona classificando as linhas individualmente ( ), e essas linhas classificadas são usadas como chaves ("assinatura" na descrição das Pérolas de Programação) para o operador principal agrupar as linhas da matriz. A expressão à direita é trem , uma forma sintática empregada pelo APL para realizar a programação tácita . Aqui, é uma sequência isolada de três funções tais que ⇔ , de onde a expressão à direita é equivalente .
{⍵[⍋⍵]}⍤1 ⊢a⌸(f g h) ⍵(f ⍵) g (h ⍵)({⍵[⍋⍵]}⍤1 ⊢a) {⊂⍵}⌸ a
Âmbito lexical
Quando um dfn interno (aninhado) se refere a um nome, ele é procurado olhando para fora através de dfns em vez de para baixo na pilha de chamadas . Diz-se que esse regime emprega escopo léxico em vez do escopo dinâmico usual do APL . A distinção torna-se aparente apenas se uma chamada for feita para uma função definida em um nível externo. Para as chamadas internas mais usuais, os dois regimes são indistinguíveis.
Por exemplo, na função a seguir which, a variável tyé definida em whichsi mesma e na função interna f1. Quando f1chama para fora f2e f2se refere a ty, ele encontra o externo (com valor 'lexical') em vez do definido em f1(com valor 'dynamic'):
which←{
ty←'lexical'
f1←{ty←'dynamic' ⋄ f2 ⍵}
f2←{ty,⍵}
f1 ⍵
}
which ' scope'
lexical scope
Guarda de erros
A função a seguir ilustra o uso de protetores de erro:
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
No APL, o erro número 5 é "erro de comprimento"; o erro número 11 é "erro de domínio"; e o número de erro 0 é um "pega-tudo" para os números de erro 1 a 999.
O exemplo mostra o desenrolar do ambiente local antes que uma expressão de proteção de erro seja avaliada. O nome local txé definido para descrever o alcance de sua seguinte proteção contra erros. Quando ocorre um erro, o ambiente é desfeito para expor txo valor estaticamente correto.
Dfns versus tradfns
Como as funções diretas são dfns, as funções APL definidas da maneira tradicional são chamadas de tradfns, pronuncia-se "trad funs". Aqui, dfns e tradfns são comparados considerando a função sieve: À esquerda está um dfn (conforme definido acima ); no meio está um tradfn usando estruturas de controle ; à direita está um tradfn usando gotos ( →) e rótulos de linha .
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 ∇ |
- Um dfn pode ser anônimo ; um tradfn deve ser nomeado.
- Um dfn é nomeado por atribuição (
←); um tradfn é nomeado incorporando o nome na representação da função e aplicando⎕fx(uma função do sistema) a essa representação. - Um dfn é mais prático do que um tradfn como operando (consulte os itens anteriores: um tradfn deve ser nomeado; um tradfn é nomeado por incorporação ...).
- Os nomes atribuídos em um dfn são locais por padrão; os nomes atribuídos em um tradfn são globais, a menos que especificados em uma lista de locais.
- Os locais em um dfn têm escopo léxico ; locais em um tradfn têm escopo dinâmico , visível nas funções chamadas, a menos que seja obscurecido por sua lista de locais.
- Os argumentos de um dfn são nomeados
⍺e⍵e os operandos de um dop são nomeados⍺⍺e⍵⍵; os argumentos e operandos de um tradfn podem ter qualquer nome, especificado em sua linha inicial. - O resultado (se houver) de um dfn não tem nome; o resultado (se houver) de um tradfn é nomeado em seu cabeçalho.
- Um valor padrão para ⍺ é especificado de forma mais precisa do que para o argumento esquerdo de um tradfn.
-
A recursão em um dfn é efetuada invocando
∇ou∇∇ou seu nome; a recursão em um tradfn é efetuada invocando seu nome. -
O controle de fluxo em um dfn é efetuado por guardas e chamadas de função; que em um tradfn é por estruturas de controle e
→(goto) e rótulos de linha. - Avaliar uma expressão em um dfn que não termina em atribuição causa o retorno do dfn; avaliar uma linha em um tradfn que não termina em atribuição ou goto exibe o resultado da linha.
- Um dfn retorna ao avaliar uma expressão que não termina em atribuição, ao avaliar uma expressão protegida ou após a última expressão; um tradfn retorna na
→(goto) linha 0 ou uma linha não existente, ou na avaliação de uma estrutura de controle, ou após a última linha.:Return - O controle de fluxo mais simples em um dfn torna mais fácil detectar e implementar a recursão de cauda do que em um tradfn.
- Um dfn pode chamar um tradfn e vice-versa ; um dfn pode ser definido em um tradfn e vice-versa .
História
Kenneth E. Iverson , o inventor do APL, estava insatisfeito com a forma como as funções do usuário (tradfns) foram definidas. Em 1974, ele desenvolveu uma "definição de função formal" ou "definição direta" para uso na exposição. Uma definição direta tem duas ou quatro partes, separadas por dois pontos:
name : expression
name : expression0 : proposition : expression1
Dentro de uma definição direta, ⍺denota o argumento esquerdo e ⍵o argumento direito. No primeiro caso, o resultado de expressioné o resultado da função; na segunda instância, o resultado da função é que expression0if propositionavalia como 0, ou expression1se avalia como 1. As atribuições dentro de uma definição direta são dinamicamente locais . Exemplos do uso de definição direta são encontrados na Conferência do Prêmio Turing de 1979 e em livros e documentos de inscrição.
A definição direta era muito limitada para uso em sistemas maiores. As ideias foram posteriormente desenvolvidas por vários autores em várias obras, mas os resultados foram difíceis de manejar. Destes, a "definição alternativa de função APL" de Bunda em 1987 foi a que mais se aproximou das instalações actuais, mas apresenta falhas em conflitos com os símbolos existentes e no tratamento de erros que teriam causado dificuldades práticas e nunca foi implementada. Os principais destilados das diferentes propostas foram que (a) a função sendo definida é anônima, com a nomenclatura subsequente (se necessária) sendo efetuada por atribuição; (b) a função é denotada por um símbolo e, portanto, permite a recursão anônima .
Em 1996, John Scholes da Dyalog Limited inventou as funções diretas (dfns). As idéias surgiram em 1989, quando ele leu uma edição especial do The Computer Journal sobre programação funcional. Ele então começou a estudar programação funcional e ficou fortemente motivado ("doente de desejo", como Yeats ) para trazer essas ideias para o APL. Ele inicialmente operou furtivamente porque estava preocupado que as mudanças pudessem ser julgadas muito radicais e uma complicação desnecessária da linguagem; outros observadores dizem que ele operou furtivamente porque os colegas de Dyalog não estavam tão apaixonados e pensaram que ele estava perdendo tempo e causando problemas para as pessoas. Os Dfns foram apresentados pela primeira vez no Dyalog Vendor Forum na APL '96 Conference e lançados no Dyalog APL no início de 1997. A aceitação e o reconhecimento demoraram a chegar. Ainda em 2008, no Dyalog aos 25 , uma publicação que celebra o 25º aniversário da Dyalog Limited, os dfns mal eram mencionados (mencionados duas vezes como "funções dinâmicas" e sem elaboração). A partir de 2019, os dfns são implementados no Dyalog APL, NARS2000 e ngn / apl. Eles também desempenham um papel fundamental nos esforços para explorar as habilidades de computação de uma unidade de processamento gráfico (GPU).
Referências
links externos
- Site oficial , Dyalog