Icon (linguagem de programação)

Icon é uma linguagem de programação interpretada de alto nível, derivada do ALGOL. Também herdou propriedades do SNOBOL 4 (processamento de cadeias de caracteres). Por ser derivada do ALGOL, faz parte de uma classe de linguagens de programação estruturadas, tendo assim, uma sintaxe similar a de C e Pascal. A partir de Icon, descende a linguagem de programação Unicon, que adiciona orientação a objetos. Icon foi implementado em C; em sua página oficial, estão disponíveis, além do código fonte e binários, alguns livros, dentre os quais um descreve o processo da implementação de Icon.

Sintaxe básica 
De muitas maneiras, Icon partilha características de uma linguagem de script: as variáveis não precisam ser declaradas, os tipos são definidos de forma automática, e os números podem ser convertidos para strings e de volta automaticamente. Outra característica comum a muitas linguagens de script, mas não a todas, é a falta de um caracter de fim de linha. Em Icon as linhas que não terminam com ponto-e-vírgula são terminadas por um ponto-e-vírgula implícito, se fizer sentido. Os procedimentos são as construções de blocos básicas na linguagem Icon, e apesar de utilizarem a sintaxe do Pascal funcionam mais como funções de C e podem retornar valores. Em Icon não há a palavra-chave function.

Uma característica interessante de Icon é que a linguagem reconheçe que em muitas computações existe mais de um valor a ser retornado. Um exemplo típico é das raízes reais de uma equação de 2° grau, que, nos casos onde o valor de delta é positivo, retorna duas respostas. Uma das operações de manipulação de cadeias de caracteres de Icon é a função find(l, s) que encontra as posições na sequência s onde l ocorre. A expressão:

 write(find("a", "banana"))

irá escrever 2. Mas a expressão:

 every write(find("a", "banana"))

irá escrever 2, 4 e 6. O motivo para isto é que a função find retorna uma sequência de resultados (2|4|6).

História 
Icon é o último de uma série de linguagens de alto nível da programação destinada a facilitar as tarefas de programação envolvendo strings e estruturas. A linguagem original, SNOBOL, foi desenvolvida no Bell Telephone Laboratories no início dos anos 1960. SNOBOL evoluiu para SNOBOL4, que ainda está em uso. Linguagens subsequentes foram desenvolvidas na Universidade do Arizona, com o apoio da National Science Foundation. Embora tenha objetivos semelhantes e muitos recursos semelhantes, Icon tem pouca semelhança superficial com SNOBOL4.

Implementações Icon foram desenvolvidas por professores, funcionários e estudantes da Universidade do Arizona, com contribuição significativa de voluntários ao redor do mundo. O Icon history de Ralph e Madge Griswold aparecem nas pré-publicações da segunda History of Programming Languages Conference (HOPL-II), ACM SIGPLAN Notices, Março de 1993 (Vol. 28, n º 3).

O nome Icon não é uma sigla, nem representam nada em particular, embora a palavra iconoclastic foi mencionado quando o nome foi escolhido. O nome precede ao uso comum de ícones para referir-se a pequenas imagens usadas em interfaces gráficas de usuário de agora. Isso às vezes induz as pessoas a pensar que Icon é projetado para criar ou manipular ícones, mas não há nenhuma boa solução para esse problema.

Características

Execução voltada a um objetivo 
Um dos conceitos chaves do Icon é que as estruturas de controle são baseadas em expressões de "sucesso" ou "falha", ao invés de lógica booleana, como na maioria das outras linguagens de programação. Sob este modelo, simples comparações como if a < b não significa "se a operação a direita for verdade" como seriam na maioria das linguagens; ao invés disso, significa algo mais parecido com "se a operação a direita for um sucesso". Nesse caso o operador < sucede se a comparação for verdadeira, então no final o resultado é o mesmo. Além disso, o operador < retorna seu segundo argumento se for bem sucedido, permitindo coisas como a < b <  c, um tipo comum de comparação que não pode ser diretamente declarada na maioria das linguagens.
A utilidade desse conceito se torna mais clara quando se considera exemplos práticos. Como Icon usa sucesso ou falha para todo o controle de fluxo, este simples código:

 if a := read() then write (a)

irá copiar uma linha da sua entrada padrão para sua saída padrão. O que é interessante sobre este exemplo é que o código irá funcionar mesmo se o read() causar um erro, por exemplo, se o arquivo não existir. Neste caso a declaração a := read() irá falhar, e write(a) simplesmente não será chamado.

Sucessos e falhas são passadas "para cima" através de funções, isso quer dizer que uma falha numa função aninhada fará com que as funções que estão chamando-a irão falhar também. Por exemplo, não podemos escrever um programa para copiar um arquivo de entrada inteiro em apenas uma linha:

 while write(read())

Quando o comando read() falhar, no final do arquivo por exemplo, a falha será transmitida até a cadeia e write() também irá falhar. O while, sendo a estrutura de controle, pára em caso de falha, o que significa que irá parar quando o arquivo estiver vazio. Para efeito de comparação, considere um exemplo semelhante escrito em pseudocódigo baseado em Java:

 try {
   while ((a = read()) != EOF) {
     write(a);
   }
 } catch (Exception e) {
   // não faz nada, sai do loop
 }

Neste caso, há duas comparações necessárias, uma para fim de arquivo (EOF) e outra para todos os outros erros. Como Java não permite que os erros sejam comparados como elementos lógicos, conforme previsto na Icon, o longa sintaxe try / catch deve ser usada. Blocos try também impõe uma penalidade de desempenho por simplesmente usá-los, mesmo se nenhum erro ocorrer, um custo distribuído que a Icon evita.

Icon refere-se a este conceito como execução voltada a um objetivo, referindo-se à maneira que a execução continua até que algum objetivo seja alcançado. No exemplo acima, o objetivo é ler todo o arquivo, o comando read() continua a ter sucesso enquanto há informações para ser lida, e falha quando não há. O objetivo é, portanto, codificado diretamente na linguagem, em vez de usar declarações para verificar códigos de retorno ou construções semelhantes.

Geradores (Generators) 
Expressões em Icon muitas vezes retornam um único valor, por exemplo, x <5 irá avaliar e ter sucesso com o valor 5 ou falhar. No entanto, vários dos exemplos abaixo dependem do fato de que muitas expressões não retornam imediatamente sucesso ou falha, retornando valores durante o mesmo. Isso leva os exemplos com every e to, every causa to a continuar a retornar os valores até que ele falhar.

Este é um conceito-chave na Icon, conhecidos como generators(geradores). Generators conduzem muitas das funcionalidades de laço na linguagem, mas fazem mais diretamente, o programador não escreve um laço depois tira e comparar os valores, Icon irá fazer de tudo isto para você.

Na linguagem de Icon, a avaliação de uma expressão ou função resulta em uma sequência de resultados. Uma sequência de resultados contém todos os valores possíveis que podem ser gerados pela expressão ou função. Quando a sequência de resultados está esgotada (por exemplo, não existem mais valores na sequência de resultados), a expressão ou função falha. Iteração sobre a sequência de resultado é obtida de forma explícita através da avaliação voltada a um objetivo do Icon ou explicitamente, por meio da cláusula every.

Icon inclui vários geradores-construtores. A sintaxe alternadora permite uma série de itens serem gerados em sequência até que um falha:

 1 | "hello" | x < 5

pode gerar "1", "hello" e "5" se x for menor que 5. Alternadores pode ser lido como "ou" em muitos casos, por exemplo:

 if y < (x | 5) then write("y=", y)

irá escrever o valor de y, se for menor do que x ou 5. Internamente Icon verifica todos os valores da esquerda para a direita até uma ser bem sucedida ou acabar a lista e ele retorna uma falha. Lembre-se que as funções não serão chamadas a menos que a chamada de dentro não falhar, de modo que este exemplo pode ser reduzido para:

 write("y=", (x | 5) > y)

Outro gerador simples é o to, que gera listas de inteiros, every write (1 to 10) irá fazer exatamente o que parece. A sintaxe-bang gera todos item de uma lista, every write (!aString) irá ter como saída cada caractere de aString em uma nova linha. Para demonstrar o poder deste conceito, considere operações com strings. A maioria das linguagens incluem uma função conhecida como find ou indexOf que retorna a localização de uma string de outra. Considere:

 s = "All the world's a stage. And all the men and women merely players";
 i = indexOf("the", s)

Este código irá retornar 4, a posição da primeira ocorrência da palavra "the". Para obter a próxima instância "the" uma forma alternativa deve ser utilizada, i = indexOf("the", s, 5) o 5 no final dizendo que ele deveria olhar a partir da posição 5 para frente. A fim de extrair todas as ocorrências de "the", um laço deve ser usado:

 s = "All the world's a stage. And all the men and women merely players";
 i = indexOf("the", s)
 while i != -1 {
   write(i);
   i =  indexOf("the", s, i+1);
 }

Em Icon a função find é um gerador, e irá retornar a próxima ocorrência da string cada vez que for reiniciada antes de finalmente falhar depois que ela passar no final da string. O mesmo código em Icon pode ser escrito:

 s := "All the world's a stage. And all the men and women merely players"
 very write(find("the",s))

find irá retornar o índice da próxima instância "the" cada vez que ele é reiniciado por every, finalmente passando pelo final da string e falhar. Como no exemplo anterior, isso fará com que write falhe, e saia do laço every. Claro que há momentos em que você deliberadamente quer encontrar uma string após algum ponto de entrada, por exemplo, você pode estar varrendo um arquivo texto contendo os dados em várias colunas. Execução voltada a um objetivo funciona aqui também, e pode ser utilizado da seguinte maneira:

 write(5 < find("the", s))

A posição só será retornada se "the" aparecer depois de posição 5, a comparação falhará caso contrário, passando a falha para write() como antes. Icon adiciona várias estruturas de controle para fazer loops dentro de geradores. O operador every é semelhante ao while, fazendo loops em cada item devolvido por um gerador e saindo em caso de falha:

 every k := i to j do
  write(someFunction(k))

Por que usar every ao invés de um laço while neste caso? Porque while reavalia o primeiro resultado, mas every produz todos os resultados. A sintaxe every na verdade injeta valores na função de forma semelhante aos blocos em Smalltalk. Por exemplo, o laço acima pode ser reescrito da seguinte maneira:

 every write(someFunction(i to j))

Os usuários podem construir novos geradores facilmente usando a palavra-chave suspend:

 procedure findOnlyOdd(pattern, theString)
   every i := find(pattern, theString) do
     if i % 2 = 1 then suspend i
 end

Este exemplo faz um loop sobre theString usando find para procurar padrões. Quando um é encontrado, e a posição é par, a localização é retornada da função com suspend. Ao contrário do return, suspend escreve onde está nos geradores internos, bem como, permitindo que ele continue onde parou na próxima iteração.

Strings 
De acordo com sua funcionalidade parecida com script, Icon adiciona uma série de recursos para tornar o trabalho com strings mais fácil. O mais notável é o sistema de varredura, que repetidamente chama funções em uma string:

s ? write(find("the"))

Nesse caso o sujeito  da função find é colocada fora dos parâmetros, em frente ao ponto de interrogação. Funções em Icon são deliberadamente (ao contrário do automático) escritas para identificar o sujeito em listas de parâmetros e permitir-lhes ser retirado desta forma. Substrings podem ser extraídas de uma string usando uma especificação de intervalo entre colchetes. A especificação de intervalo pode retornar um ponto para um único caractere, ou um pedaço da string. Strings podem ser indexadas tanto da direita quanto da esquerda. É importante observar que as posições dentro de uma sequência estão entre os caracteres 1A2B3C4 e podem ser especificados a partir da direita -3A-2B-1C0.

Por exemplo:
 "Wikipedia"[1]     ⇒ "W"
 "Wikipedia"[3]     ⇒ "k"
 "Wikipedia"[0]     ⇒ "a"
 "Wikipedia"[1:3]   ⇒ "Wi"
 "Wikipedia"[-2:0]  ⇒ "ia"
 "Wikipedia"[2+:3]  ⇒ "iki"

Onde o último exemplo mostra o uso de um comprimento, em vez de uma posição final.

A especificação de subscripting pode ser usado como um Lvalue dentro de uma expressão. Isso pode ser usado para inserir uma string em outra string ou apagar partes de uma string. Por exemplo:

 s := "abc"
 s[2] := "123"
 agora s tem o valor "a123c"
 s := "abcdefg"
 s[3:5] := "ABCD"
 agora s tem o valor "abABCDefg"
 s := "abcdefg"
 s[3:5] := ""
 agora s tem o valor "abefg"

Outras estruturas 
Icon também permite ao usuário facilmente construir suas próprias listas (ou arrays):

 aCat := ["muffins", "malhado", 2002, 8]

Os itens de uma lista podem ser de qualquer tipo, incluindo outras estruturas. Para criar rapidamente listas maiores, o Icon inclui o gerador de lista; i := list (10, "palavra") gera uma lista contendo 10 cópias de "palavra". Como arrays em outras linguagens, Icon permite que itens sejam pesquisados por posição, por exemplo, peso: = aCat [4]. A sintaxe-bang, por exemplo, every write (!aCat), irá imprimir quatro linhas, cada uma com um elemento. Icon inclui funções como pilha, push e pop que lhes permitam formar a base de pilhas e filas. Icon também inclui uma funcionalidade para os conjuntos e tabelas (conhecido como hashes, arrays associativos, dicionários, etc.):

 simbolos := table(0)
 simbolos["ali"] := 1
 simbolos["aqui"] := 2

Esse código cria uma tabela que vai usar zero como o valor padrão de uma chave desconhecida. Em seguida, adiciona dois itens nela, com as chaves "ali" e "aqui", e os valores 1 e 2.

Exemplos de códigos

Programa Olá Mundo 

procedure main()
   write("Olá, Mundo!")
end

N-primeiros números perfeitos 
Um exemplo de código que encontra os n primeiros números perfeitos:

procedure main()
   write("Digite a quantidade de numeros perfeitos:")

   n := read()
   i := 2
   qtd := 0

   while qtd < n do {
      soma := 0	
      j := 1
      while j < i do {
         if i%j = 0 then
            soma := j + soma			
         j := j + 1
      }

      if soma = i then{
         write(i)
         qtd := qtd +1
      }
      i := i + 1
   }
end

Ver também 
 Linguagem de programação
 Lista de linguagens de programação
 Unicon

Bibliografia 
 The Icon Programming Language (terceira edição) por Ralph E. Griswold and Madge T. Griswold, ISBN 1-57398-001-3.

Ligações externas 
 
 
 

Domínio público
Linguagens de programação
Software de domínio público