Projeto Euler – Pausa

Uma pequena pausa apenas para respirar. Mas já podemos fazer um pequeno resumo de alguns detalhas vistos nos artigos anteriores.

1. As operações realizadas da direita para a esquerda. Não deve ser problema para ninguém mas pode exigir um pouco de atenção. Os parênteses podem ser utilizados para mudar a precedência das operações. Por exemplo:

3*5+1

18

(3*5)+1

16

2. A linguagem possui grande flexibilidade para trabalhar com matrizes e não é necessário a criação de laços para a interação com os elementos.

2 3 4 + 4 5 6

6 8 10

2 * 1 2 3

2 4 6

É necessário que o elemento da esquerda possua o mesmo número de itens do elemento da direita para não ocorrer um erro ou ser um e será aplicado a todos os elementos do vetor.

2 3 + 4 5 6

|length error

| 2 3 +4 5 6

3. A linguagem possui uma nomenclatura específica, mais parecendo uma linguagem natural voltada para uma aplicação específica (DSL). A relação mais simples seria do verbo que pode ser comparado as funções ou operadores de outras linguagens. Mas a utilização de um advérbio modifica o modo como o verbo ira interagir com um determinado trecho. Pode ser difícil no início mas, com o tempo, vai se tornando mais fácil de se entender os programas. A gente também demora um pouco para aprender a ler e escrever. É por aí, mas não é uma coisa do outro mundo. Muitos já usam estruturas bem complicadas como expressões regulares. Outros conseguem complicar linguagens como Ruby apenas para deixar tudo em uma linha de código deixando o código de leitura complicada.

*/ 1 2 3 => 1 * 2 * 3

6

4. Pelos fatores anteriores aliados ao fato do vocabulário possuir verbos que aceitam 1 ou dois argumentos, até a leitura do manual se torna mais complicada. Um mesmo verbo pode significar operação totalmente diferente conforme o contexto. Como foi falado em linguagem natural antes, o mesmo ocorre no uso diário da nossa língua. Você pode assistir um jogo ou pode assistir a um jogo. Almoçar a mesa e jantar na mesa. O mesmo ocorre com J. Você pode ver no vocabulário que # pode significar Tally ou Copy. Conforme a construção você terá uma resposta.

# 1 2 3 NB. caso 1

3

2 # 1 2 3 NB. caso 2

1 1 2 2 3 3

1 0 1 # 1 2 3 NB. caso 3

1 3

2 1 2 # 1 2 3 NB. caso 3

1 1 2 3 3

No caso 1, # é Tally e retorna o comprimento de um, no caso, vetor.

No caso 2 e 3, # é Copy e irá copiar os elementos do vetor x conforme o valor de y. Se for um, todos os elementos de y serão copiados x vezes. Outra opção é que x e y sejam do mesmo tamanho e cada elemento correspondente de y será copiado x vezes. X deve ser maior ou igual a zero.

5. É possível definir outros verbos (como se fosse funções em outras linguagens). Eles podem aceitar um ou dois argumentos (monad e dyad). Considere (também para a leitura do manual quando necessário) que o formato é x v y, isto é o valor da esquerda é x e o da direita é y.

dobro=.3 : '2*y'

dobro 4

8

dxmy=.4 : 'y+2*x'

2 dxmy 3

7

dobro 2 3 4

4 6 8

No caso de dxmy (2x+y) poderia ser definida como ‘(2*x)+y’ por casa da avaliação da direita para esquerda. Construções mais complexas também podem ser definidas facilmente e de forma bastante legível utilizando as estruturas de controle (for. if. while. else. end. break. continue.)

fib=: 3 : 0

if. 1>:y do.

y

else.

(fibx y-1)+fibx y-2

end.

)

fibx 10

55

Depois é só chamar fib 10 para o resultado. É claro que a ‘função’ , mesmo sendo um exemplo clássico é extremamente ineficiente para número grandes (o que não é um problema específico de J). Fugindo um pouco, podemos utilizar M. (memoization) para acelerar o processo, o que nos permite calcular rapidamente o número de fibonacci de argumentos maiores. Não tente fib 250 com a função anterior (não sei se vai demorar dois dias ou se irá acusar estouro de pilha antes).

fib=: 3 : 0 M.

if. 1>:y do. y else. (fib y-1)+fib y-2 end.

)

x: fibx 250

7896325826131730509282738943634332893686268675876375

O x: permite efetuar os cálculos com precisão estendida. Também é possível adicionar x ao número.

fib 250

7.89633e51

!20

2.4329e18

!20x

2432902008176640000

7. A geração de um intervalo de Inteiros é dada por i.n. Bastante utilizada em diversas situações. Alguns exemplos.

i.5

0 1 2 3 4

i._5

4 3 2 1 0

>:i.5

1 2 3 4 5

10+i.5

10 11 12 13 14

i.2 3

0 1 2

3 4 5

Acho que não adianta repetir tudo que está no manual e outras documentações. A melhor maneira de aprender J é pensar em J. É claro que no início é normal utilizar estruturas de controle e escrever algo que poderia ser escrito em outra linguagem qualquer e, provavelmente, com perda de performance. Mas para isso é necessário um bom conhecimento da linguagem (coisa que não é adquirida do dia para a noite). De certa forma me lembra o emacs. Faz de tudo mas requer um bom tempo para aprender tudo (uma vida?). Em um tópico do fórum de J está escrito:

… I suspect you won’t /learn/ (all of) J in a week (perhaps in a life), but I imagine you’ll be doing quite a few impressive things pretty quickly. …

Garimpar no wiki, pesquisar no fórum, ler a documentação e procurar entender exemplos escritos por outros programadores mais experientes, entre outras coisas, irá fazer com que você entenda a linguagem e/ou tenha ideias para adaptar procedimentos para outras linguagens. Não é uma linguagem fácil, mas é um ambiente que trará muitas surpresas (no bom sentido) para quem resolver pagar o preço do aprendizado.

Se você tem uma ideia de C, está disponível (entre outros) o livro J for C Programmers que é um bom começo (ótima leitura para um final de semana).

Anúncios