Unixtopia

main/ artigos/

Lisp

Constitui uma família de linguagens de programação minimalistas, como Common Lisp, Scheme ou Clojure, descendentes da linguagem Lisp criada por John McCarthy. Dado o grande número de diferentes linguagens Lisp, chamadas dialetos, que surgiram do Lisp original ao longo do caminho, é difícil fazer afirmações gerais sobre todas elas, mas daremos uma visão geral.Linguagens Lisp se baseiam no paradigma funcional e no cálculo lambda, embora não imponham estritamente a programação funcional, os efeitos colaterais das funções ainda são permitidos, assim como os paradigmas imperativos e outros, são de alto nível, mas simples, dinâmicas e flexíveis, tipadas dinamicamente, geralmente interpretadas, ou compiladas para bytecode, embora algumas também compilem para código nativo, coletam lixo e usam uma notação de prefixo com colchetes. Muitos hackers consideram Lisp o auge da beleza minimalistas, Lisp compete principalmente com Forth, outra linguagem extremamente minimalista. Embora o Forth vença em termos de desempenho e por ser mais adequado ao hardware típico, o Lisp é a linguagem mais elegante do ponto de vista matemático, é o sonho do matemático. Alan Kay chegou a chamá-lo de "Equações de Maxwell do software" quando viu que poderia ser descrita em uma única página.

Ao contrário do Forth, o Lisp não está entre as linguagens mais rápidas, o Emacs é em grande parte, escrito em Lisp, mas tem que contar com C para partes críticas de desempenho, devido à sobrecarga da tipagem dinâmica e da alta abstração, como números arbitrariamente precisos e coleta de lixo, mas é preciso dizer que o Lisp pode ser executado excepcionalmente rápido em hardware especial feito para executar o Lisp, costumava haver tais máquinas, chamadas Lisp Machines, mas perderam a popularidade. Lisp é famoso por empregar número excessivo de colchetes, por isso Lispers geralmente são sensíveis à formatação adequada do código. É usado como uma linguagem de script para extensões, como no Emacs ou GIMP. As Lisps normalmente empregam avaliação rigorosa, avaliam todos os parâmetros da função, sejam eles necessários ou não, assim como linguagens imperativas convencionais, em vez das puramente funcionais, isso se deve ao fato de que o paradigma puramente funcional não é imposto, e as construções imperativas são suportadas, embora desencorajadas. Isso tira um pouco da elegância, pois agora é necessário que existam as chamadas formas especiais, construções que se parecem sintaticamente com funções, mas são exceções em relação ao comportamento das funções normais, enquanto funções normais sempre têm todos os seus parâmetros avaliados, o if branch é uma forma especial que avalia apenas um determinado ramo, dependendo da condição, avaliar todos os argumentos levaria à execução de ambos ramos.

Linguagens estritamente funcionais, como Haskell, não sofrem com isso, mas Lisp quebra essa regra com maestria permitindo mais praticidade, pois encontrou um bom equilíbrio entre a imposição de regras e a remoção de limitações. Parte da filosofia e paradigma Lisp é que o programa e os dados são representados da mesma forma, há pouca distinção entre código e dados, ambos são listas ou, em termos Lisp, expressões simbólicas entre colchetes, em que o primeiro símbolo é entendido como o operador ou função e o restante são seus argumentos. Isso permite construir dinamicamente um programa e executá-lo em tempo de execução. O Lisp também tem vários sistemas de macros que permitem estender a linguagem em movimento, de forma similar ao Forth, é possível criar novas estruturas de controle. Lisp é high-level, mas minimalista, um caso raro de se ver, uma combinação incomum, ao menos atualmente, mas não é uma má combinação, linguagens high-level não são necessariamente malignas, é que high-level implica em bloat. Lisp consegue se manter agradável, a linguagem é definida de forma abstrata, tratando os valores na memória como entidades abstratas em vez de sequências de bits, não incomodando o programador com o gerenciamento de memória. Isso geralmente é otimizado posteriormente por compiladores ou intérpretes para um código mais amigável à máquina, mas o programador não precisa se preocupar com isso, basta que ele conheça o comportamento abstrato.

Claro que há penalidades, ignorar o que está acontecendo por trás das cortinas sempre tem um preço, masLisp faz essa escolha de bom grado e a implementa de modo a obter as vantagens do high-level e, ao mesmo tempo, minimizar penalidades, a linguagem é projetada de modo que possa ser implementada de forma minimalista. Então, basicamente, poderíamos chamar o Lisp de uma linguagem high-level bem feita. Como os dialetos se diferenciam? De muitas maneiras diferentes, alguns se concentram no pragmatismo, outros no minimalismo, outros adicionam suas próprias extensões e recursos, outros modificam a própria linguagem, enquanto outros apenas fornecem bibliotecas adicionais, outros apenas dão mais ênfase a coisas diferentes, outros tentam oferecer suporte a mais paradigmas, como OOP, e outros apenas tentam fazer as coisas de maneira diferente. Vamos examinar Common Lisp versus Scheme. O Common Lisp é mais bloated e tem uma grande biblioteca padrão, o Scheme é minimalista, impõe que a recursão de cauda seja otimizada, incentiva mais a programação funcional, não especifica a ordem de avaliação dos argumentos, o Common Lisp avalia os argumentos da esquerda para a direita e oferece suporte ao escopo dinâmico, enquanto Scheme oferece suporte apenas ao escopo lexical. Para alguém que vem do mundo do C, onde C é simplesmente C, esse mundo pode provocar um choque cultural e uma sobrecarga de informações, há diferentes dialetos de Lisp, cada um com padrões diferentes, cada um com implementações diferentes. Mas há riqueza, evolução e muitas opções. Alguns dos dialetos mais notáveis da lista incluem.

Detalhes do Scheme

Há vários padrões de Scheme, sendo que os mais notáveis são os Revised Report^N on the Algorithmic Language Scheme, em que N é um número inteiro, que é abreviado como rNrs. Parece que o mais clássico é o r5rs de 98, no qual adotaremos. Como já foi dito, basicamente todo construto em Lisp tem a forma f a1 a2, em que f é uma função e a1, a2 são argumentos, que têm o mesmo formato ou representam algum valor atômico, como um número ou uma cadeia de caracteres. O que em C escreveríamos como myVariable = myFunction(1,2,strLen("abc")) em Lisp escrevemos como (set! myVariable (myFunction 1 2 (strLen "abc"))). Esse formato se aplica a estruturas de controle, macros e assim por diante. Há muitas implementações de Scheme, como scm, mit-scheme ou Guile. Escolheremos o scm aqui. Para executar um código-fonte do Scheme a partir de um arquivo, faça scm -f source.scm.

Quanto aos tipos de dados, o Scheme e o Lisp é tipado dinamicamente, os valores têm tipos de dados, mas as variáveis não, é possível atribuir qualquer valor a qualquer variável e a verificação de tipo ocorre em tempo de execução. Todas as variáveis podem ser vistas como ponteiros para um tipo de objeto geral, que contém informações sobre seu tipo. Os tipos de dados incluem.