Lisp Comum - Common Lisp
Paradigma | Multi-paradigma : procedimental , funcional , orientado a objetos , meta , reflexivo , genérico |
---|---|
Família | Lisp |
Projetado por | Scott Fahlman , Richard P. Gabriel , David A. Moon , Kent Pitman , Guy Steele , Dan Weinreb |
Desenvolvedor | ANSI X3J13 comitê |
Apareceu pela primeira vez | 1984 | , 1994 para ANSI Common Lisp
Disciplina de digitação | Dinâmico , forte |
Alcance | Lexical, opcionalmente dinâmico |
SO | Plataforma cruzada |
Extensões de nome de arquivo | .lisp, .lsp, .l, .cl, .fasl |
Local na rede Internet | common-lisp |
Implementações principais | |
Allegro CL , ABCL , CLISP , Clozure CL , CMUCL , ECL , GCL , LispWorks , Scieneer CL , SBCL , Symbolics Common Lisp | |
Dialetos | |
CLtL1, CLtL2, ANSI Common Lisp | |
Influenciado por | |
Lisp , Lisp Máquina Lisp , Maclisp , Scheme , Interlisp | |
Influenciado | |
Clojure , Dylan , Emacs Lisp , EuLisp , ISLISP , * Lisp , AutoLisp , Julia , Moose , R , SKILL , SubL |
Common Lisp ( CL ) é um dialeto da linguagem de programação Lisp , publicado em ANSI documento padrão ANSI INCITS 226-1994 (S20018) (anteriormente X3.226-1994 (R1999) ). O Common Lisp HyperSpec , uma versão HTML com hiperlink, foi derivado do padrão ANSI Common Lisp.
A linguagem Common Lisp foi desenvolvida como uma sucessora padronizada e aprimorada de Maclisp . No início dos anos 1980, vários grupos já estavam trabalhando em diversos sucessores de MacLisp: Lisp Machine Lisp (também conhecido como ZetaLisp), Spice Lisp , NIL e S-1 Lisp . O Common Lisp buscou unificar, padronizar e estender os recursos desses dialetos MacLisp. Common Lisp não é uma implementação, mas sim uma especificação de linguagem . Várias implementações do padrão Common Lisp estão disponíveis, incluindo software livre e de código aberto e produtos proprietários. Common Lisp é uma linguagem de programação multiparadigma de propósito geral . Ele oferece suporte a uma combinação de paradigmas de programação procedural , funcional e orientada a objetos . Como uma linguagem de programação dinâmica , ela facilita o desenvolvimento de software evolutivo e incremental , com compilação iterativa em programas de tempo de execução eficientes. Esse desenvolvimento incremental geralmente é feito de forma interativa, sem interromper o aplicativo em execução.
Ele também suporta anotação de tipo opcional e conversão, que podem ser adicionados conforme necessário nas fases posteriores de criação de perfil e otimização, para permitir que o compilador gere um código mais eficiente. Por exemplo, fixnum
pode conter um inteiro não encaixotado em um intervalo suportado pelo hardware e implementação, permitindo aritmética mais eficiente do que em números inteiros grandes ou tipos de precisão arbitrária. Da mesma forma, o compilador pode ser informado por módulo ou por função sobre o tipo de nível de segurança desejado, usando declarações de otimização .
Common Lisp inclui CLOS , um sistema de objetos que suporta multimétodos e combinações de métodos. Geralmente é implementado com um protocolo de metaobjeto .
Common Lisp é extensível por meio de recursos padrão, como macros Lisp (transformações de código) e macros de leitura (analisadores de entrada para caracteres).
Common Lisp fornece compatibilidade parcial com versões anteriores com Maclisp e Lisp original de John McCarthy . Isso permite que software Lisp mais antigo seja portado para Common Lisp.
História
O trabalho no Common Lisp começou em 1981 após uma iniciativa do gerente do ARPA Bob Engelmore para desenvolver um único dialeto Lisp padrão da comunidade. Muito do design inicial da linguagem foi feito por meio de correio eletrônico. Em 1982, Guy L. Steele Jr. deu a primeira visão geral do Common Lisp no Simpósio ACM de 1982 sobre LISP e programação funcional.
A primeira documentação da linguagem foi publicada em 1984 como Common Lisp the Language (conhecido como CLtL1), primeira edição. Uma segunda edição (conhecida como CLtL2), publicada em 1990, incorporou muitas mudanças na linguagem, feitas durante o processo de padronização do ANSI Common Lisp: sintaxe LOOP estendida, o Common Lisp Object System, o Condition System para tratamento de erros, uma interface para o impressora bonita e muito mais. Mas CLtL2 não descreve o padrão ANSI Common Lisp final e, portanto, não é uma documentação do ANSI Common Lisp. O padrão ANSI Common Lisp final foi então publicado em 1994. Desde então, nenhuma atualização do padrão foi publicada. Várias extensões e melhorias para Common Lisp (exemplos são Unicode, Concurrency, CLOS-based IO) foram fornecidas por implementações e bibliotecas.
Sintaxe
Lisp comum é um dialeto do Lisp. Ele usa expressões S para denotar a estrutura de código e de dados. Chamadas de função, macro formulários e formulários especiais são escritos como listas, com o nome do operador primeiro, como nestes exemplos:
(+ 2 2) ; adds 2 and 2, yielding 4. The function's name is '+'. Lisp has no operators as such.
(defvar *x*) ; Ensures that a variable *x* exists,
; without giving it a value. The asterisks are part of
; the name, by convention denoting a special (global) variable.
; The symbol *x* is also hereby endowed with the property that
; subsequent bindings of it are dynamic, rather than lexical.
(setf *x* 42.1) ; Sets the variable *x* to the floating-point value 42.1
;; Define a function that squares a number:
(defun square (x)
(* x x))
;; Execute the function:
(square 3) ; Returns 9
;; The 'let' construct creates a scope for local variables. Here
;; the variable 'a' is bound to 6 and the variable 'b' is bound
;; to 4. Inside the 'let' is a 'body', where the last computed value is returned.
;; Here the result of adding a and b is returned from the 'let' expression.
;; The variables a and b have lexical scope, unless the symbols have been
;; marked as special variables (for instance by a prior DEFVAR).
(let ((a 6)
(b 4))
(+ a b)) ; returns 10
Tipos de dados
Lisp comum tem muitos tipos de dados .
Tipos escalares
Número tipos incluem inteiros , proporções , números de ponto flutuante , e números complexos . Common Lisp usa bignums para representar valores numéricos de tamanho e precisão arbitrários. O tipo de proporção representa exatamente as frações, um recurso não disponível em muitos idiomas. O Common Lisp força automaticamente os valores numéricos entre esses tipos, conforme apropriado.
O tipo de caractere Common Lisp não está limitado a caracteres ASCII . A maioria das implementações modernas permite caracteres Unicode .
O tipo de símbolo é comum às linguagens Lisp, mas amplamente desconhecido fora delas. Um símbolo é um objeto de dados nomeado exclusivo com várias partes: nome, valor, função, lista de propriedades e pacote. Destes, a célula de valor e a célula de função são as mais importantes. Símbolos em Lisp são freqüentemente usados de forma semelhante a identificadores em outras linguagens: para manter o valor de uma variável; no entanto, existem muitos outros usos. Normalmente, quando um símbolo é avaliado, seu valor é retornado. Alguns símbolos são avaliados por si próprios, por exemplo, todos os símbolos no pacote de palavras-chave são autoavaliados. Os valores booleanos em Common Lisp são representados pelos símbolos de autoavaliação T e NIL. Common Lisp possui namespaces para símbolos, chamados 'pacotes'.
Várias funções estão disponíveis para arredondar valores numéricos escalares de várias maneiras. A função round
arredonda o argumento para o número inteiro mais próximo, com casos intermediários arredondados para o número inteiro par. As funções truncate
, floor
e são ceiling
arredondadas para zero, para baixo ou para cima, respectivamente. Todas essas funções retornam a parte fracionária descartada como um valor secundário. Por exemplo, (floor -2.5)
produz −3, 0,5; (ceiling -2.5)
produz −2, −0,5; (round 2.5)
produz 2, 0,5; e (round 3.5)
produz 4, −0,5.
Estruturas de dados
Os tipos de sequência no Common Lisp incluem listas, vetores, vetores de bits e strings. Existem muitas operações que podem funcionar em qualquer tipo de sequência.
Como em quase todos os outros dialetos Lisp, as listas em Common Lisp são compostas de conses , às vezes chamados de células cons ou pares . Um contras é uma estrutura de dados com dois slots, chamados de carro e cdr . Uma lista é uma cadeia ligada de conses ou a lista vazia. Cada carro dos contras refere-se a um membro da lista (possivelmente outra lista). Cada cdr de contras se refere às próximas contras - exceto para as últimas contras em uma lista, cujo cdr se refere ao nil
valor. Conses também podem ser facilmente usados para implementar árvores e outras estruturas de dados complexas; embora seja geralmente aconselhável usar instâncias de estrutura ou classe. Também é possível criar estruturas de dados circulares com contras.
Common Lisp oferece suporte a matrizes multidimensionais e pode redimensionar matrizes ajustáveis dinamicamente, se necessário. Matrizes multidimensionais podem ser usadas para matemática de matrizes. Um vetor é uma matriz unidimensional. Os arrays podem carregar qualquer tipo como membros (até mesmo tipos mistos no mesmo array) ou podem ser especializados para conter um tipo específico de membros, como em um vetor de bits. Normalmente, apenas alguns tipos são suportados. Muitas implementações podem otimizar funções de array quando o array usado é especializado em tipo. Dois tipos de matriz especializado do tipo padrão são: uma cadeia é um vector de caracteres, ao passo que um bit-vector é um vector de pedaços .
As tabelas de hash armazenam associações entre objetos de dados. Qualquer objeto pode ser usado como chave ou valor. As tabelas de hash são redimensionadas automaticamente conforme necessário.
Pacotes são coleções de símbolos, usados principalmente para separar as partes de um programa em namespaces . Um pacote pode exportar alguns símbolos, marcando-os como parte de uma interface pública. Os pacotes podem usar outros pacotes.
Estruturas , semelhantes em uso a estruturas C e registros Pascal , representam estruturas de dados complexas arbitrárias com qualquer número e tipo de campos (chamados slots ). Estruturas permitem herança única.
As classes são semelhantes às estruturas, mas oferecem recursos mais dinâmicos e herança múltipla. (Veja CLOS ). As classes foram adicionadas posteriormente ao Common Lisp e há alguma sobreposição conceitual com estruturas. Objetos criados de classes são chamados de Instâncias . Um caso especial são as Funções Genéricas. Funções genéricas são funções e instâncias.
Funções
Common Lisp suporta funções de primeira classe . Por exemplo, é possível escrever funções que recebem outras funções como argumentos ou funções de retorno também. Isso torna possível descrever operações muito gerais.
A biblioteca Common Lisp depende muito dessas funções de ordem superior. Por exemplo, a sort
função recebe um operador relacional como um argumento e a função chave como um argumento de palavra-chave opcional. Isso pode ser usado não apenas para classificar qualquer tipo de dados, mas também para classificar estruturas de dados de acordo com uma chave.
;; Sorts the list using the > and < function as the relational operator.
(sort (list 5 2 6 3 1 4) #'>) ; Returns (6 5 4 3 2 1)
(sort (list 5 2 6 3 1 4) #'<) ; Returns (1 2 3 4 5 6)
;; Sorts the list according to the first element of each sub-list.
(sort (list '(9 A) '(3 B) '(4 C)) #'< :key #'first) ; Returns ((3 B) (4 C) (9 A))
O modelo de avaliação de funções é muito simples. Quando o avaliador encontra um formulário (f a1 a2...)
, ele presume que o símbolo denominado f é um dos seguintes:
- Um operador especial (facilmente verificado em uma lista fixa)
- Um operador macro (deve ter sido definido anteriormente)
- O nome de uma função (padrão), que pode ser um símbolo ou um subformulário que começa com o símbolo
lambda
.
Se f for o nome de uma função, os argumentos a1, a2, ..., an são avaliados da esquerda para a direita e a função é encontrada e chamada com os valores fornecidos como parâmetros.
Definindo funções
A macrodefun
define funções em que uma definição de função fornece o nome da função, os nomes de quaisquer argumentos e um corpo de função:
(defun square (x)
(* x x))
As definições de função podem incluir diretivas de compilador , conhecidas como declarações , que fornecem dicas ao compilador sobre as configurações de otimização ou os tipos de dados dos argumentos. Eles também podem incluir strings de documentação (docstrings), que o sistema Lisp pode usar para fornecer documentação interativa:
(defun square (x)
"Calculates the square of the single-float x."
(declare (single-float x) (optimize (speed 3) (debug 0) (safety 1)))
(the single-float (* x x)))
Funções anônimas ( literais de função ) são definidas usando lambda
expressões, por exemplo, (lambda (x) (* x x))
para uma função que quadrada seu argumento. O estilo de programação Lisp freqüentemente usa funções de ordem superior para as quais é útil fornecer funções anônimas como argumentos.
As funções locais podem ser definidas com flet
e labels
.
(flet ((square (x)
(* x x)))
(square 3))
Existem vários outros operadores relacionados à definição e manipulação de funções. Por exemplo, uma função pode ser compilada com o compile
operador. (Alguns sistemas Lisp executam funções usando um interpretador por padrão, a menos que sejam instruídos a compilar; outros compilam todas as funções).
Definição de funções e métodos genéricos
A macro defgeneric
define funções genéricas . Funções genéricas são uma coleção de métodos . A macro defmethod
define métodos.
Métodos podem especializar seus parâmetros sobre CLOS classes padrão , classes de sistema , classes de estrutura ou objetos individuais. Para muitos tipos, existem classes de sistema correspondentes .
Quando uma função genérica é chamada, o envio múltiplo determinará o método eficaz a ser usado.
(defgeneric add (a b))
(defmethod add ((a number) (b number))
(+ a b))
(defmethod add ((a vector) (b number))
(map 'vector (lambda (n) (+ n b)) a))
(defmethod add ((a vector) (b vector))
(map 'vector #'+ a b))
(defmethod add ((a string) (b string))
(concatenate 'string a b))
(add 2 3) ; returns 5
(add #(1 2 3 4) 7) ; returns #(8 9 10 11)
(add #(1 2 3 4) #(4 3 2 1)) ; returns #(5 5 5 5)
(add "COMMON " "LISP") ; returns "COMMON LISP"
Funções genéricas também são um tipo de dados de primeira classe . Existem muito mais recursos para Funções e Métodos Genéricos do que os descritos acima.
O namespace da função
O namespace para nomes de funções é separado do namespace para variáveis de dados. Esta é uma diferença chave entre Common Lisp e Scheme . Para Lisp comum, operadores que definem nomes no namespace função incluem defun
, flet
, labels
, defmethod
e defgeneric
.
Para passar uma função por nome como um argumento para outra função, deve-se usar o function
operador especial, comumente abreviado como #'
. O primeiro sort
exemplo acima se refere à função nomeada pelo símbolo >
no namespace da função, com o código #'>
. Por outro lado, para chamar uma função passada dessa forma, seria usado o funcall
operador no argumento.
O modelo de avaliação do Scheme é mais simples: há apenas um namespace e todas as posições no formulário são avaliadas (em qualquer ordem) - não apenas os argumentos. O código escrito em um dialeto é, portanto, às vezes confuso para programadores mais experientes no outro. Por exemplo, muitos programadores do Common Lisp gostam de usar nomes de variáveis descritivos, como lista ou string, que podem causar problemas no Scheme, pois fariam localmente ocultar nomes de funções.
Se um namespace separado para funções é uma vantagem, é uma fonte de contenção na comunidade Lisp. É normalmente referido como o debate Lisp-1 vs. Lisp-2 . Lisp-1 se refere ao modelo de Scheme e Lisp-2 se refere ao modelo de Common Lisp. Esses nomes foram cunhados em um artigo de 1988 por Richard P. Gabriel e Kent Pitman , que compara extensivamente as duas abordagens.
Vários valores de retorno
Common Lisp suporta o conceito de múltiplos valores , onde qualquer expressão sempre tem um único valor primário , mas também pode ter qualquer número de valores secundários , que podem ser recebidos e inspecionados por chamadores interessados. Esse conceito é diferente de retornar um valor de lista, pois os valores secundários são totalmente opcionais e passados por meio de um canal lateral dedicado. Isso significa que os chamadores podem permanecer totalmente inconscientes da existência de valores secundários, se não precisarem deles, e torna conveniente usar o mecanismo de comunicação de informações que às vezes é útil, mas nem sempre necessário. Por exemplo,
- A
TRUNCATE
função arredonda o número fornecido para um inteiro em direção a zero. No entanto, ele também retorna um resto como um valor secundário, tornando muito fácil determinar qual valor foi truncado. Ele também suporta um parâmetro divisor opcional, que pode ser usado para realizar a divisão euclidiana trivialmente:
(let ((x 1266778)
(y 458))
(multiple-value-bind (quotient remainder)
(truncate x y)
(format nil "~A divided by ~A is ~A remainder ~A" x y quotient remainder)))
;;;; => "1266778 divided by 458 is 2765 remainder 408"
-
GETHASH
retorna o valor de uma chave em um mapa associativo , ou o valor padrão caso contrário, e um booleano secundário indicando se o valor foi encontrado. Assim, o código que não se importa se o valor foi encontrado ou fornecido como padrão pode simplesmente usá-lo no estado em que se encontra, mas quando tal distinção for importante, ele pode inspecionar o booleano secundário e reagir apropriadamente. Ambos os casos de uso são suportados pela mesma chamada e nenhum é desnecessariamente sobrecarregado ou restringido pelo outro. Ter esse recurso no nível do idioma elimina a necessidade de verificar a existência da chave ou compará-la com o valor nulo, como seria feito em outros idiomas.
(defun get-answer (library)
(gethash 'answer library 42))
(defun the-answer-1 (library)
(format nil "The answer is ~A" (get-answer library)))
;;;; Returns "The answer is 42" if ANSWER not present in LIBRARY
(defun the-answer-2 (library)
(multiple-value-bind (answer sure-p)
(get-answer library)
(if (not sure-p)
"I don't know"
(format nil "The answer is ~A" answer))))
;;;; Returns "I don't know" if ANSWER not present in LIBRARY
Vários valores são suportados por um punhado de formulários padrão, os mais comuns dos quais são o MULTIPLE-VALUE-BIND
formulário especial para acessar valores secundários e VALUES
para retornar vários valores:
(defun magic-eight-ball ()
"Return an outlook prediction, with the probability as a secondary value"
(values "Outlook good" (random 1.0)))
;;;; => "Outlook good"
;;;; => 0.3187
Outros tipos
Outros tipos de dados em Common Lisp incluem:
- Os nomes de caminho representam arquivos e diretórios no sistema de arquivos . O recurso de nome de caminho Common Lisp é mais geral do que as convenções de nomenclatura de arquivos da maioria dos sistemas operacionais, tornando o acesso dos programas Lisp a arquivos amplamente portável em diversos sistemas.
- Os fluxos de entrada e saída representam fontes e coletores de dados binários ou textuais, como o terminal ou arquivos abertos.
- O Common Lisp possui um gerador de números pseudo-aleatórios (PRNG) integrado . Objetos de estado aleatório representam fontes reutilizáveis de números pseudo-aleatórios, permitindo ao usuário propagar o PRNG ou fazer com que ele reproduza uma sequência.
- Condições são um tipo usado para representar erros, exceções e outros eventos "interessantes" aos quais um programa pode responder.
- As classes são objetos de primeira classe e, elas próprias, instâncias de classes chamadas classes de metaobjetos ( metaclasses para abreviar).
- Readtables são um tipo de objeto que controla como o leitor do Common Lisp analisa o texto do código-fonte. Ao controlar qual legível está em uso quando o código é lido, o programador pode alterar ou estender a sintaxe da linguagem.
Alcance
Como programas em muitas outras linguagens de programação, os programas Common Lisp usam nomes para se referir a variáveis, funções e muitos outros tipos de entidades. As referências nomeadas estão sujeitas ao escopo.
A associação entre um nome e a entidade à qual o nome se refere é chamada de ligação.
O escopo se refere ao conjunto de circunstâncias nas quais um nome é determinado como tendo uma ligação específica.
Determinantes de escopo
As circunstâncias que determinam o escopo em Common Lisp incluem:
- a localização de uma referência em uma expressão. Se for a posição mais à esquerda de um composto, ele se refere a um operador especial ou a uma macro ou vinculação de função, caso contrário, a uma vinculação de variável ou outra coisa.
- o tipo de expressão em que a referência ocorre. Por exemplo,
(go x)
significa que transfere o controle para o rótulox
, enquanto(print x)
se refere à variávelx
. Ambos os escopos dex
podem estar ativos na mesma região do texto do programa, uma vez que os rótulos de tagbody estão em um namespace separado dos nomes de variáveis. Uma forma especial ou forma de macro tem controle total sobre os significados de todos os símbolos em sua sintaxe. Por exemplo, em(defclass x (a b) ())
, uma definição de classe, o(a b)
é uma lista de classes base, então esses nomes são procurados no espaço de nomes de classes ex
não são uma referência a uma associação existente, mas o nome de uma nova classe sendo derivada dea
eb
. Esses fatos emergem puramente da semântica dedefclass
. O único fato genérico sobre essa expressão é quedefclass
se refere a uma ligação de macro; tudo o mais dependedefclass
. - a localização da referência dentro do texto do programa. Por exemplo, se uma referência à variável
x
estiver incluída em um construto de ligação, como umlet
que define uma ligação parax
, então a referência está no escopo criado por essa ligação. - para uma referência de variável, se um símbolo de variável foi ou não, local ou globalmente, declarado especial. Isso determina se a referência é resolvida em um ambiente léxico ou em um ambiente dinâmico.
- a instância específica do ambiente em que a referência é resolvida. Um ambiente é um dicionário de tempo de execução que mapeia símbolos para ligações. Cada tipo de referência usa seu próprio tipo de ambiente. As referências a variáveis lexicais são resolvidas em um ambiente lexical, etc. Mais de um ambiente pode ser associado à mesma referência. Por exemplo, graças à recursão ou ao uso de vários threads, várias ativações da mesma função podem existir ao mesmo tempo. Essas ativações compartilham o mesmo texto de programa, mas cada uma tem sua própria instância de ambiente lexical.
Para entender a que um símbolo se refere, o programador do Common Lisp deve saber que tipo de referência está sendo expressa, que tipo de escopo ela usa se for uma referência de variável (escopo dinâmico versus léxico), e também a situação de tempo de execução: em qual ambiente é a referência resolvida, onde a ligação foi introduzida no ambiente, etc.
Tipos de ambiente
Global
Alguns ambientes em Lisp são globalmente difundidos. Por exemplo, se um novo tipo for definido, ele será conhecido em todos os lugares a partir de então. As referências a esse tipo podem ser encontradas neste ambiente global.
Dinâmico
Um tipo de ambiente em Common Lisp é o ambiente dinâmico. As ligações estabelecidas neste ambiente têm extensão dinâmica, o que significa que uma ligação é estabelecida no início da execução de alguma construção, como um let
bloco, e desaparece quando essa construção termina de ser executada: seu tempo de vida está vinculado à ativação e desativação dinâmica de um bloco. No entanto, uma vinculação dinâmica não é apenas visível dentro desse bloco; também é visível para todas as funções invocadas daquele bloco. Esse tipo de visibilidade é conhecido como escopo indefinido. Ligações que exibem extensão dinâmica (tempo de vida vinculado à ativação e desativação de um bloco) e escopo indefinido (visível para todas as funções que são chamadas desse bloco) são consideradas como tendo escopo dinâmico.
O Common Lisp tem suporte para variáveis de escopo dinâmico, que também são chamadas de variáveis especiais. Certos outros tipos de vínculos também têm necessariamente escopo dinâmico, como reinicializações e tags de captura. Os vínculos de função não podem ter escopo dinâmico usando flet
(que fornece apenas vínculos de função com escopo léxico), mas os objetos de função (um objeto de primeiro nível no Common Lisp) podem ser atribuídos a variáveis com escopo dinâmico, vinculados usando let
no escopo dinâmico e, em seguida, chamados usando funcall
ou APPLY
.
O escopo dinâmico é extremamente útil porque adiciona clareza referencial e disciplina às variáveis globais . Variáveis globais são desaprovadas na ciência da computação como fontes potenciais de erro, porque podem dar origem a canais de comunicação ad-hoc e secretos entre módulos que levam a interações indesejadas e surpreendentes.
Em Common Lisp, uma variável especial que possui apenas uma associação de nível superior se comporta como uma variável global em outras linguagens de programação. Um novo valor pode ser armazenado nele e esse valor simplesmente substitui o que está na ligação de nível superior. A substituição descuidada do valor de uma variável global está no cerne dos bugs causados pelo uso de variáveis globais. No entanto, outra maneira de trabalhar com uma variável especial é fornecer a ela uma nova vinculação local dentro de uma expressão. Isso às vezes é chamado de "religação" da variável. Vincular uma variável com escopo dinâmico cria temporariamente um novo local de memória para essa variável e associa o nome a esse local. Enquanto essa associação estiver em vigor, todas as referências a essa variável se referem à nova associação; a ligação anterior está oculta. Quando a execução da expressão de ligação termina, o local da memória temporária desaparece e a ligação antiga é revelada, com o valor original intacto. Obviamente, várias ligações dinâmicas para a mesma variável podem ser aninhadas.
Em implementações Common Lisp que suportam multithreading, escopos dinâmicos são específicos para cada thread de execução. Assim, as variáveis especiais servem como uma abstração para o armazenamento local do thread. Se um thread religar uma variável especial, essa religação não terá efeito sobre essa variável em outros threads. O valor armazenado em uma ligação só pode ser recuperado pelo encadeamento que criou essa ligação. Se cada thread vincula alguma variável especial *x*
, então *x*
se comporta como armazenamento local de thread. Entre os encadeamentos que não são religados *x*
, ele se comporta como um global comum: todos esses encadeamentos referem-se à mesma ligação de nível superior de *x*
.
Variáveis dinâmicas podem ser usadas para estender o contexto de execução com informações de contexto adicionais que são passadas implicitamente de função para função sem ter que aparecer como um parâmetro de função extra. Isso é especialmente útil quando a transferência de controle precisa passar por camadas de código não relacionado, que simplesmente não podem ser estendidas com parâmetros extras para passar os dados adicionais. Uma situação como essa geralmente exige uma variável global. Essa variável global deve ser salva e restaurada, para que o esquema não seja interrompido por recursão: a religação da variável dinâmica cuida disso. E essa variável deve ser feita no local do segmento (ou então um grande mutex deve ser usado) para que o esquema não seja interrompido sob os segmentos: as implementações de escopo dinâmico também podem cuidar disso.
Na biblioteca Common Lisp, existem muitas variáveis especiais padrão. Por exemplo, todos os fluxos de E / S padrão são armazenados nas ligações de nível superior de variáveis especiais conhecidas. O fluxo de saída padrão é armazenado em * saída padrão *.
Suponha que uma função foo grave na saída padrão:
(defun foo ()
(format t "Hello, world"))
Para capturar sua saída em uma string de caracteres, * standard-output * pode ser vinculado a um stream de string e chamado:
(with-output-to-string (*standard-output*)
(foo))
-> "Hello, world" ; gathered output returned as a string
Lexical
Lisp comum suporta ambientes lexicais. Formalmente, as ligações em um ambiente léxico têm escopo léxico e podem ter uma extensão indefinida ou dinâmica, dependendo do tipo de namespace. Âmbito lexical significa que a visibilidade está fisicamente restrita ao bloco em que a encadernação é estabelecida. As referências que não são textualmente (ou seja, lexicamente) embutidas nesse bloco simplesmente não veem essa ligação.
As tags em um TAGBODY têm escopo léxico. A expressão (GO X) é errônea se não estiver embutida em um TAGBODY que contém um rótulo X. No entanto, as associações de rótulos desaparecem quando o TAGBODY encerra sua execução, porque têm extensão dinâmica. Se esse bloco de código for inserido novamente pela invocação de um fechamento léxico , é inválido para o corpo desse fechamento tentar transferir o controle para uma tag via GO:
(defvar *stashed*) ;; will hold a function
(tagbody
(setf *stashed* (lambda () (go some-label)))
(go end-label) ;; skip the (print "Hello")
some-label
(print "Hello")
end-label)
-> NIL
Quando o TAGBODY é executado, ele primeiro avalia a forma setf que armazena uma função na variável especial * escondida *. Então o (go end-label) transfere o controle para o end-label, pulando o código (imprima "Hello"). Uma vez que end-label está no final do tagbody, o tagbody termina, produzindo NIL. Suponha que a função lembrada anteriormente agora seja chamada:
(funcall *stashed*) ;; Error!
Esta situação é errônea. A resposta de uma implementação é uma condição de erro que contém a mensagem, "GO: tagbody para a tag SOME-LABEL já foi deixada". A função tentou avaliar (go some-label), que está lexicamente embutido no tagbody e resolve para o rótulo. No entanto, o tagbody não está executando (sua extensão terminou) e, portanto, a transferência de controle não pode ocorrer.
As associações de função local no Lisp têm escopo léxico e as associações de variáveis também têm escopo léxico por padrão. Em contraste com os rótulos GO, ambos têm extensão indefinida. Quando uma função lexical ou ligação variável é estabelecida, essa ligação continua a existir enquanto as referências a ela forem possíveis, mesmo após o construto que estabeleceu essa ligação ter terminado. Referências a variáveis e funções lexicais após o término de sua construção de estabelecimento são possíveis graças a fechamentos lexicais .
A vinculação lexical é o modo de vinculação padrão para variáveis Common Lisp. Para um símbolo individual, ele pode ser alternado para o escopo dinâmico, seja por uma declaração local, seja por uma declaração global. O último pode ocorrer implicitamente por meio do uso de uma construção como DEFVAR ou DEFPARAMETER. É uma convenção importante na programação Common Lisp que variáveis especiais (isto é, com escopo dinâmico) tenham nomes que começam e terminam com um símbolo de asterisco *
no que é chamado de " convenção de proteção para os ouvidos ". Se cumprida, essa convenção cria efetivamente um namespace separado para variáveis especiais, de modo que as variáveis que pretendem ser lexicais não sejam acidentalmente tornadas especiais.
O escopo lexical é útil por vários motivos.
Em primeiro lugar, as referências a variáveis e funções podem ser compiladas para um código de máquina eficiente, porque a estrutura do ambiente de tempo de execução é relativamente simples. Em muitos casos, ele pode ser otimizado para empilhar o armazenamento, portanto, abrir e fechar escopos lexicais tem sobrecarga mínima. Mesmo nos casos em que é necessário gerar fechamentos totais, o acesso ao ambiente do fechamento ainda é eficiente; normalmente, cada variável se torna um deslocamento em um vetor de ligações e, portanto, uma referência de variável torna-se uma instrução de carga ou armazenamento simples com um modo de endereçamento base mais deslocamento .
Em segundo lugar, o escopo lexical (combinado com extensão indefinida) dá origem ao fechamento lexical , que por sua vez cria todo um paradigma de programação centrado em torno do uso de funções como objetos de primeira classe, que está na raiz da programação funcional.
Em terceiro lugar, talvez o mais importante, mesmo que os fechamentos lexicais não sejam explorados, o uso do escopo lexical isola os módulos do programa de interações indesejadas. Devido à sua visibilidade restrita, as variáveis lexicais são privadas. Se um módulo A vincula uma variável lexical X e chama outro módulo B, as referências a X em B não resolverão acidentalmente o limite X em A. B simplesmente não tem acesso a X. Para situações em que as interações disciplinadas por meio de uma variável são desejável, Common Lisp fornece variáveis especiais. Variáveis especiais permitem que um módulo A estabeleça uma ligação para uma variável X que é visível para outro módulo B, chamado de A. Poder fazer isso é uma vantagem, e poder evitar que isso aconteça também é uma vantagem; conseqüentemente, Common Lisp suporta escopo léxico e dinâmico .
Macros
Uma macro em Lisp se parece superficialmente com uma função em uso. No entanto, em vez de representar uma expressão que é avaliada, representa uma transformação do código-fonte do programa. A macro obtém a fonte que cerca como argumentos, vincula-os aos seus parâmetros e calcula uma nova forma de fonte. Este novo formulário também pode usar uma macro. A expansão da macro é repetida até que o novo formulário de origem não use uma macro. A forma final computada é o código-fonte executado em tempo de execução.
Usos típicos de macros em Lisp:
- novas estruturas de controle (exemplo: construções de loop, construções de ramificação)
- escopo e construtos de ligação
- sintaxe simplificada para código-fonte complexo e repetido
- formulários de definição de nível superior com efeitos colaterais em tempo de compilação
- programação baseada em dados
- linguagens específicas de domínio incorporado (exemplos: SQL , HTML , Prolog )
- formulários de finalização implícita
Vários recursos padrão do Common Lisp também precisam ser implementados como macros, como:
- a
setf
abstração padrão , para permitir expansões personalizadas em tempo de compilação de operadores de atribuição / acesso -
with-accessors
,with-slots
,with-open-file
E outros semelhantesWITH
macros - Dependendo da implementação,
if
oucond
é uma macro construída na outra, o operador especial;when
eunless
consistem em macros - A poderosa
loop
linguagem específica de domínio
As macros são definidas pela macro defmacro . O operador especial macrolet permite a definição de macros locais (com escopo léxico). Também é possível definir macros para símbolos usando define-symbol-macro e symbol-macrolet .
O livro On Lisp de Paul Graham descreve o uso de macros em Common Lisp em detalhes. O livro Let Over Lambda de Doug Hoyte estende a discussão sobre macros, afirmando que "As macros são a maior vantagem que o lisp tem como linguagem de programação e a maior vantagem de qualquer linguagem de programação." Hoyte fornece vários exemplos de desenvolvimento iterativo de macros.
Exemplo de uso de macro para definir uma nova estrutura de controle
As macros permitem que os programadores Lisp criem novas formas sintáticas na linguagem. Um uso típico é criar novas estruturas de controle. A macro de exemplo fornece uma until
construção de loop. A sintaxe é:
(until test form*)
A definição macro para até :
(defmacro until (test &body body)
(let ((start-tag (gensym "START"))
(end-tag (gensym "END")))
`(tagbody ,start-tag
(when ,test (go ,end-tag))
(progn ,@body)
(go ,start-tag)
,end-tag)))
tagbody é um operador especial Common Lisp primitivo que fornece a capacidade de nomear tags e usar o formulário go para pular para essas tags. O acento grave ` fornece uma notação que proporciona modelos de código, onde o valor de formas precedida com uma vírgula são preenchidos. Formas precedida com vírgula e no-sinal são emendados em. A forma tagbody testa a condição final. Se a condição for verdadeira, ele pula para a tag final. Caso contrário, o código do corpo fornecido é executado e, em seguida, salta para a tag de início.
Um exemplo de uso da macro até acima :
(until (= (random 10) 0)
(write-line "Hello"))
O código pode ser expandido usando a função macroexpand-1 . A expansão do exemplo acima se parece com isto:
(TAGBODY
#:START1136
(WHEN (ZEROP (RANDOM 10))
(GO #:END1137))
(PROGN (WRITE-LINE "hello"))
(GO #:START1136)
#:END1137)
Durante a expansão da macro, o valor do teste da variável é (= (aleatório 10) 0) e o valor do corpo da variável é ((linha de escrita "Olá")) . O corpo é uma lista de formulários.
Os símbolos geralmente são eliminados automaticamente. A expansão usa o TAGBODY com duas etiquetas. Os símbolos para essas etiquetas são calculados por GENSYM e não estão incluídos em nenhum pacote. Dois formulários go usam essas tags para acessar . Visto que tagbody é um operador primitivo em Common Lisp (e não uma macro), ele não será expandido para outra coisa. A forma expandida usa a macro quando , que também será expandida. Expandir totalmente um formulário de origem é chamado de code walking .
Na forma totalmente expandida ( percorrida ), a forma quando é substituída pela primitiva se :
(TAGBODY
#:START1136
(IF (ZEROP (RANDOM 10))
(PROGN (GO #:END1137))
NIL)
(PROGN (WRITE-LINE "hello"))
(GO #:START1136))
#:END1137)
Todas as macros devem ser expandidas antes que o código-fonte que as contém possa ser avaliado ou compilado normalmente. As macros podem ser consideradas funções que aceitam e retornam expressões S - semelhantes às árvores de sintaxe abstratas , mas não se limitam a elas. Essas funções são chamadas antes do avaliador ou compilador para produzir o código-fonte final. As macros são escritas em Common Lisp normal e podem usar qualquer operador Common Lisp (ou de terceiros) disponível.
Captura variável e sombreamento
As macros Lisp comuns são capazes do que é comumente chamado de captura de variável , onde os símbolos no corpo da macroexpansão coincidem com aqueles no contexto de chamada, permitindo ao programador criar macros em que vários símbolos têm um significado especial. O termo captura de variável é um tanto enganoso, porque todos os namespaces são vulneráveis à captura indesejada, incluindo o namespace de operador e função, o namespace de rótulo de tagbody, tag catch, manipulador de condição e namespaces de reinicialização.
A captura variável pode apresentar defeitos de software. Isso acontece de uma das seguintes maneiras:
- Na primeira forma, uma expansão de macro pode inadvertidamente fazer uma referência simbólica que o criador da macro presumiu que resolverá em um namespace global, mas o código onde a macro é expandida fornece uma definição local sombreada que rouba essa referência. Que isso seja referido como captura do tipo 1.
- A segunda maneira, a captura do tipo 2, é exatamente o oposto: alguns dos argumentos da macro são pedaços de código fornecidos pelo chamador da macro, e esses pedaços de código são escritos de forma que façam referências às ligações circundantes. No entanto, a macro insere esses pedaços de código em uma expansão que define suas próprias ligações que capturam acidentalmente algumas dessas referências.
O dialeto Scheme do Lisp fornece um sistema de escrita de macro que fornece a transparência referencial que elimina ambos os tipos de problema de captura. Este tipo de macrossistema é por vezes denominado "higiénico", em particular pelos seus proponentes (que consideram os macrossistemas que não resolvem automaticamente este problema como anti-higiénicos).
No Common Lisp, a macro higiene é garantida de duas maneiras diferentes.
Uma abordagem é usar academias : símbolos exclusivos garantidos que podem ser usados em uma expansão macro sem ameaça de captura. O uso de academias em uma definição de macro é uma tarefa manual, mas macros podem ser escritas, o que simplifica a instanciação e o uso de academias. As academias resolvem a captura do tipo 2 facilmente, mas não são aplicáveis à captura do tipo 1 da mesma maneira, porque a expansão da macro não pode renomear os símbolos de interferência no código circundante que capturam suas referências. Os ginásios podem ser usados para fornecer apelidos estáveis para os símbolos globais necessários à expansão macro. A expansão da macro usaria esses apelidos secretos em vez dos nomes conhecidos, portanto, a redefinição dos nomes conhecidos não teria nenhum efeito prejudicial na macro.
Outra abordagem é usar pacotes. Uma macro definida em seu próprio pacote pode simplesmente usar símbolos internos nesse pacote em sua expansão. O uso de pacotes trata da captura do tipo 1 e do tipo 2.
No entanto, os pacotes não resolvem a captura tipo 1 de referências a funções e operadores Common Lisp padrão. A razão é que o uso de pacotes para resolver problemas de captura gira em torno do uso de símbolos privados (símbolos em um pacote, que não são importados para, ou de outra forma tornados visíveis em outros pacotes). Considerando que os símbolos da biblioteca Common Lisp são externos e freqüentemente importados ou tornados visíveis em pacotes definidos pelo usuário.
A seguir está um exemplo de captura indesejada no namespace do operador, ocorrendo na expansão de uma macro:
;; expansion of UNTIL makes liberal use of DO
(defmacro until (expression &body body)
`(do () (,expression) ,@body))
;; macrolet establishes lexical operator binding for DO
(macrolet ((do (...) ... something else ...))
(until (= (random 10) 0) (write-line "Hello")))
A until
macro se expandirá em uma forma que chama do
que se destina a se referir à macro Common Lisp padrão do
. No entanto, neste contexto, do
pode ter um significado completamente diferente, portanto, until
pode não funcionar corretamente.
Common Lisp resolve o problema do sombreamento de operadores e funções padrão proibindo sua redefinição. Como ele redefine o operador padrão do
, o precedente é na verdade um fragmento do Common Lisp não conforme, que permite que as implementações o diagnostiquem e rejeitem.
Sistema de condição
O sistema de condição é responsável pelo tratamento de exceções no Common Lisp. Ele fornece condições , manipuladores e reinicializações . As condições são objetos que descrevem uma situação excepcional (por exemplo, um erro). Se uma condição for sinalizada, o sistema Common Lisp procura um manipulador para esse tipo de condição e chama o manipulador. O manipulador agora pode pesquisar reinicializações e usar uma dessas reinicializações para reparar automaticamente o problema atual, usando informações como o tipo de condição e qualquer informação relevante fornecida como parte do objeto de condição e chamar a função de reinicialização apropriada.
Essas reinicializações, se não tratadas por código, podem ser apresentadas aos usuários (como parte de uma interface de usuário, a de um depurador, por exemplo), para que o usuário possa selecionar e chamar uma das reinicializações disponíveis. Uma vez que o tratador de condição é chamado no contexto do erro (sem desfazer a pilha), a recuperação total do erro é possível em muitos casos, onde outros sistemas de tratamento de exceção já teriam encerrado a rotina atual. O próprio depurador também pode ser personalizado ou substituído usando a *debugger-hook*
variável dinâmica. O código encontrado em formulários de proteção de desenrolamento , como finalizadores, também será executado conforme apropriado, apesar da exceção.
No exemplo a seguir (usando o Symbolics Genera ) o usuário tenta abrir um arquivo em um teste de função Lisp chamado de Read-Eval-Print-LOOP ( REPL ), quando o arquivo não existe. O sistema Lisp apresenta quatro reinicializações. O usuário seleciona Repetir ABRIR usando uma reinicialização de nome de caminho diferente e insere um nome de caminho diferente (lispm-init.lisp em vez de lispm-int.lisp). O código do usuário não contém nenhum código de tratamento de erros. Todo o tratamento de erros e o código de reinicialização são fornecidos pelo sistema Lisp, que pode tratar e reparar o erro sem encerrar o código do usuário.
Command: (test ">zippy>lispm-int.lisp")
Error: The file was not found.
For lispm:>zippy>lispm-int.lisp.newest
LMFS:OPEN-LOCAL-LMFS-1
Arg 0: #P"lispm:>zippy>lispm-int.lisp.newest"
s-A, <Resume>: Retry OPEN of lispm:>zippy>lispm-int.lisp.newest
s-B: Retry OPEN using a different pathname
s-C, <Abort>: Return to Lisp Top Level in a TELNET server
s-D: Restart process TELNET terminal
-> Retry OPEN using a different pathname
Use what pathname instead [default lispm:>zippy>lispm-int.lisp.newest]:
lispm:>zippy>lispm-init.lisp.newest
...the program continues
Common Lisp Object System (CLOS)
Common Lisp inclui um kit de ferramentas para programação orientada a objetos , o Common Lisp Object System ou CLOS , que é um dos mais poderosos sistemas de objetos disponíveis em qualquer linguagem. Por exemplo, Peter Norvig explica como muitos Design Patterns são mais simples de implementar em uma linguagem dinâmica com os recursos do CLOS (herança múltipla, mixins, multimétodos, metaclasses, combinações de métodos, etc.). Várias extensões para Common Lisp para programação orientada a objetos foram propostas para serem incluídas no padrão ANSI Common Lisp, mas eventualmente CLOS foi adotado como o sistema de objetos padrão para Common Lisp. CLOS é um sistema de objetos dinâmicos com envio múltiplo e herança múltipla , e difere radicalmente dos recursos OOP encontrados em linguagens estáticas como C ++ ou Java . Como um sistema de objetos dinâmicos, o CLOS permite mudanças em tempo de execução para funções e classes genéricas. Métodos podem ser adicionados e removidos, classes podem ser adicionadas e redefinidas, objetos podem ser atualizados para mudanças de classe e a classe de objetos pode ser alterada.
CLOS foi integrado em ANSI Common Lisp. As funções genéricas podem ser usadas como funções normais e são um tipo de dados de primeira classe. Cada classe CLOS é integrada ao sistema de tipo Common Lisp. Muitos tipos de Lisp comuns têm uma classe correspondente. Há mais uso potencial do CLOS para Common Lisp. A especificação não diz se as condições são implementadas com CLOS. Os nomes de caminho e fluxos podem ser implementados com CLOS. Essas outras possibilidades de uso do CLOS para ANSI Common Lisp não fazem parte do padrão. As implementações reais do Common Lisp usam CLOS para nomes de caminho, fluxos, entrada-saída, condições, a implementação do próprio CLOS e muito mais.
Compilador e intérprete
Um interpretador Lisp executa diretamente o código-fonte Lisp fornecido como objetos Lisp (listas, símbolos, números, ...) lidos de expressões-s. Um compilador Lisp gera bytecode ou código de máquina a partir do código -fonte Lisp. O Common Lisp permite que funções individuais do Lisp sejam compiladas na memória e a compilação de arquivos inteiros em código compilado armazenado externamente ( arquivos fasl ).
Várias implementações de dialetos Lisp anteriores forneceram um interpretador e um compilador. Infelizmente, muitas vezes a semântica era diferente. Esses Lisps anteriores implementaram escopo léxico no compilador e escopo dinâmico no interpretador. O Common Lisp requer que tanto o interpretador quanto o compilador usem escopo léxico por padrão. O padrão Common Lisp descreve a semântica do interpretador e de um compilador. O compilador pode ser chamado usando a função compile para funções individuais e usando a função compile-file para arquivos. Common Lisp permite declarações de tipo e fornece maneiras de influenciar a política de geração de código do compilador. Para o último, várias qualidades de otimização podem receber valores entre 0 (não importante) e 3 (mais importante): velocidade , espaço , segurança , depuração e velocidade de compilação .
Há também uma função para avaliar o código Lisp: eval
. eval
aceita o código como expressões S pré-analisadas e não, como em algumas outras linguagens, como strings de texto. Desta forma, o código pode ser construído com as funções usuais do Lisp para a construção de listas e símbolos e, em seguida, esse código pode ser avaliado com a função eval
. Várias implementações do Common Lisp (como Clozure CL e SBCL) estão implementando eval
usando seu compilador. Desta forma, o código é compilado, embora seja avaliado usando a função eval
.
O compilador de arquivo é invocado usando a função compile-file . O arquivo gerado com o código compilado é chamado de arquivo fasl (de carregamento rápido ). Esses arquivos fasl e também os arquivos de código-fonte podem ser carregados com a função load em um sistema Common Lisp em execução. Dependendo da implementação, o compilador de arquivo gera byte-code (por exemplo para a Java Virtual Machine ), código de linguagem C (que então é compilado com um compilador C) ou, diretamente, código nativo.
Implementações Common Lisp podem ser usadas interativamente, mesmo que o código seja totalmente compilado. A ideia de uma linguagem interpretada, portanto, não se aplica ao Common Lisp interativo.
A linguagem faz uma distinção entre tempo de leitura, tempo de compilação, tempo de carregamento e tempo de execução, e permite que o código do usuário também faça essa distinção para executar o tipo de processamento desejado na etapa desejada.
Alguns operadores especiais são fornecidos para se adequar especialmente ao desenvolvimento interativo; por exemplo, defvar
só atribuirá um valor à sua variável fornecida se ela ainda não estiver vinculada, enquanto defparameter
sempre executará a atribuição. Essa distinção é útil ao avaliar, compilar e carregar o código de forma interativa em uma imagem ao vivo.
Alguns recursos também são fornecidos para ajudar a escrever compiladores e interpretadores. Os símbolos consistem em objetos de primeiro nível e são diretamente manipuláveis pelo código do usuário. O progv
operador especial permite criar ligações léxicas programaticamente, enquanto os pacotes também são manipuláveis. O compilador Lisp está disponível em tempo de execução para compilar arquivos ou funções individuais. Isso facilita o uso do Lisp como um compilador ou interpretador intermediário para outra linguagem.
Exemplos de código
Paradoxo do aniversário
O programa a seguir calcula o menor número de pessoas em uma sala para as quais a probabilidade de aniversários únicos é inferior a 50% (o paradoxo do aniversário , onde para 1 pessoa a probabilidade é obviamente 100%, para 2 é 364/365, etc. ) A resposta é 23.
Por convenção, constantes em Common Lisp são incluídas com caracteres +.
(defconstant +year-size+ 365)
(defun birthday-paradox (probability number-of-people)
(let ((new-probability (* (/ (- +year-size+ number-of-people)
+year-size+)
probability)))
(if (< new-probability 0.5)
(1+ number-of-people)
(birthday-paradox new-probability (1+ number-of-people)))))
Chamando a função de exemplo usando o REPL (Read Eval Print Loop):
CL-USER > (birthday-paradox 1.0 1)
23
Classificando uma lista de objetos pessoais
Definimos uma classe person
e um método para exibir o nome e a idade de uma pessoa. Em seguida, definimos um grupo de pessoas como uma lista de person
objetos. Em seguida, iteramos sobre a lista classificada.
(defclass person ()
((name :initarg :name :accessor person-name)
(age :initarg :age :accessor person-age))
(:documentation "The class PERSON with slots NAME and AGE."))
(defmethod display ((object person) stream)
"Displaying a PERSON object to an output stream."
(with-slots (name age) object
(format stream "~a (~a)" name age)))
(defparameter *group*
(list (make-instance 'person :name "Bob" :age 33)
(make-instance 'person :name "Chris" :age 16)
(make-instance 'person :name "Ash" :age 23))
"A list of PERSON objects.")
(dolist (person (sort (copy-list *group*)
#'>
:key #'person-age))
(display person *standard-output*)
(terpri))
Ele imprime os três nomes com idade decrescente.
Bob (33)
Ash (23)
Chris (16)
Exponenciando por quadratura
O uso da macro LOOP é demonstrado:
(defun power (x n)
(loop with result = 1
while (plusp n)
when (oddp n) do (setf result (* result x))
do (setf x (* x x)
n (truncate n 2))
finally (return result)))
Exemplo de uso:
CL-USER > (power 2 200)
1606938044258990275541962092341162602522202993782792835301376
Compare com a exponenciação embutida:
CL-USER > (= (expt 2 200) (power 2 200))
T
Encontre a lista de shells disponíveis
WITH-OPEN-FILE é uma macro que abre um arquivo e fornece um fluxo. Quando o formulário está retornando, o arquivo é fechado automaticamente. FUNCALL chama um objeto de função. O LOOP coleta todas as linhas que correspondem ao predicado.
(defun list-matching-lines (file predicate)
"Returns a list of lines in file, for which the predicate applied to
the line returns T."
(with-open-file (stream file)
(loop for line = (read-line stream nil nil)
while line
when (funcall predicate line)
collect it)))
A função AVAILABLE-SHELLS chama a função LIST-MATCHING-LINES acima com um nome de caminho e uma função anônima como predicado. O predicado retorna o nome do caminho de um shell ou NIL (se a string não for o nome do arquivo de um shell).
(defun available-shells (&optional (file #p"/etc/shells"))
(list-matching-lines
file
(lambda (line)
(and (plusp (length line))
(char= (char line 0) #\/)
(pathname
(string-right-trim '(#\space #\tab) line))))))
Resultados de exemplo (no Mac OS X 10.6):
CL-USER > (available-shells)
(#P"/bin/bash" #P"/bin/csh" #P"/bin/ksh" #P"/bin/sh" #P"/bin/tcsh" #P"/bin/zsh")
Comparação com outros Lisps
Lisp comum é mais frequentemente comparado e contrastado com Scheme - se apenas porque eles são os dois dialetos Lisp mais populares. Scheme antecede CL e vem não apenas da mesma tradição Lisp, mas de alguns dos mesmos engenheiros - Guy L. Steele , com quem Gerald Jay Sussman projetou Scheme, presidiu o comitê de padrões para Common Lisp.
Common Lisp é uma linguagem de programação de propósito geral, em contraste com variantes do Lisp, como Emacs Lisp e AutoLISP, que são linguagens de extensão embutidas em produtos específicos (GNU Emacs e AutoCAD, respectivamente). Ao contrário de muitos Lisps anteriores, Common Lisp (como Scheme ) usa escopo de variável lexical por padrão para código interpretado e compilado.
A maioria dos sistemas Lisp cujos designs contribuíram para Common Lisp - como ZetaLisp e Franz Lisp - usaram variáveis com escopo dinâmico em seus interpretadores e variáveis com escopo léxico em seus compiladores. Scheme introduziu o uso exclusivo de variáveis com escopo léxico para Lisp; uma inspiração do ALGOL 68 . CL também suporta variáveis com escopo dinâmico, mas elas devem ser declaradas explicitamente como "especiais". Não há diferenças no escopo entre interpretadores ANSI CL e compiladores.
Common Lisp é algumas vezes denominado Lisp-2 e Scheme como Lisp-1 , referindo-se ao uso do CL de namespaces separados para funções e variáveis. (Na verdade, CL tem muitos namespaces, como aqueles para tags go, nomes de bloco e loop
palavras - chave). Há uma controvérsia de longa data entre os defensores do CL e do Scheme sobre as compensações envolvidas em vários namespaces. No Scheme, é (amplamente) necessário evitar dar nomes de variáveis que conflitem com as funções; As funções de esquema freqüentemente têm argumentos nomeados lis
, lst
ou lyst
para não entrar em conflito com a função do sistema list
. No entanto, em CL, é necessário referir-se explicitamente ao namespace da função ao passar uma função como um argumento - o que também é uma ocorrência comum, como no sort
exemplo acima.
CL também difere de Scheme no tratamento de valores booleanos. Scheme usa os valores especiais #t e #f para representar a verdade e a falsidade. CL segue a convenção Lisp mais antiga de usar os símbolos T e NIL, com NIL representando também a lista vazia. Em CL, qualquer valor não NIL é tratado como verdadeiro por condicionais, como if
, enquanto no Esquema todos os valores não # f são tratados como verdade. Essas convenções permitem que alguns operadores em ambas as linguagens sirvam como predicados (respondendo a uma pergunta com valor booleano) e retornando um valor útil para cálculos adicionais, mas no Esquema o valor '() que é equivalente a NIL em Common Lisp é avaliado como verdadeiro em uma expressão booleana.
Por último, os documentos de padrões do Esquema requerem otimização de chamada final , o que o padrão CL não exige . A maioria das implementações de CL oferece otimização de chamada final, embora frequentemente apenas quando o programador usa uma diretiva de otimização. No entanto, o estilo de codificação comum CL não favorece o uso ubíquo de recursão que o estilo Esquema prefere-o que um programador Esquema expressaria com recursão de cauda, um usuário CL normalmente expressam com uma expressão iterativa em do
, dolist
, loop
, ou (mais recentemente) com o iterate
pacote.
Implementações
Veja as implementações de Category Common Lisp .
Common Lisp é definido por uma especificação (como Ada e C ) em vez de uma implementação (como Perl ). Existem muitas implementações e as áreas de detalhes padrão nas quais eles podem diferir validamente.
Além disso, as implementações tendem a vir com extensões, que fornecem funcionalidades não abordadas no padrão:
- Nível superior interativo (REPL)
- Coleta de lixo
- Depurador, Stepper e Inspector
- Estruturas de dados fracas (tabelas hash)
- Sequências extensíveis
- LOOP extensível
- Acesso ao ambiente
- Protocolo de meta-objeto CLOS
- Streams extensíveis baseados em CLOS
- Sistema de Condição baseado em CLOS
- Streams de rede
- CLOS persistente
- Suporte Unicode
- Interface de idioma estrangeiro (geralmente para C)
- Interface do sistema operacional
- Interface Java
- Threads e multiprocessamento
- Entrega de aplicativos (aplicativos, bibliotecas dinâmicas)
- Salvando imagens
Bibliotecas de software livre e de código aberto foram criadas para suportar extensões para Common Lisp de uma forma portátil e são encontradas mais notavelmente nos repositórios dos projetos Common-Lisp.net e CLOCC (Common Lisp Open Code Collection).
As implementações Common Lisp podem usar qualquer combinação de compilação de código nativo, compilação de código de byte ou interpretação. Common Lisp foi projetado para suportar compiladores incrementais , compiladores de arquivo e compiladores de bloco. Declarações padrão para otimizar a compilação (como inlining de função ou especialização de tipo) são propostas na especificação da linguagem. As implementações mais comuns do Lisp compilam o código-fonte para o código de máquina nativo . Algumas implementações podem criar aplicativos autônomos (otimizados). Outros compilam para bytecode interpretado , que é menos eficiente do que o código nativo, mas facilita a portabilidade do código binário. Alguns compiladores compilam código Common Lisp para código C. O equívoco de que Lisp é uma linguagem puramente interpretada é mais provável porque os ambientes Lisp fornecem um prompt interativo e que o código é compilado um por um, de forma incremental. Com Common Lisp, a compilação incremental é amplamente utilizada.
Algumas implementações baseadas em Unix ( CLISP , SBCL ) podem ser usadas como linguagem de script ; isto é, invocado pelo sistema de forma transparente da maneira que um interpretador de shell Perl ou Unix é.
Lista de implementações
Implementações comerciais
- Allegro Common Lisp
- para Microsoft Windows, FreeBSD, Linux, Apple macOS e várias variantes do UNIX. Allegro CL fornece um Ambiente de Desenvolvimento Integrado (IDE) (para Windows e Linux) e recursos abrangentes para entrega de aplicativos.
- Lisp comum líquido
- anteriormente chamado de Lucid Common Lisp . Apenas manutenção, sem novos lançamentos.
- LispWorks
- para Microsoft Windows, FreeBSD, Linux, Apple macOS, iOS, Android e várias variantes do UNIX. LispWorks fornece um Ambiente de Desenvolvimento Integrado (IDE) (disponível para a maioria das plataformas, mas não para iOS e Android) e recursos abrangentes para entrega de aplicativos.
- mocl
- para iOS, Android e macOS.
- Open Genera
- para DEC Alpha.
- Scieneer Common Lisp
- que é projetado para computação científica de alto desempenho.
Implementações livremente redistribuíveis
- Armed Bear Common Lisp (ABCL)
- Uma implementação de CL que é executada na Java Virtual Machine . Inclui um compilador para código de bytes Java e permite acesso a bibliotecas Java a partir do CL. Anteriormente, era apenas um componente do Armed Bear J Editor .
- CLISP
- Uma implementação de compilação de bytecode, portátil e executada em vários sistemas Unix e semelhantes (incluindo macOS ), bem como Microsoft Windows e vários outros sistemas.
- Clozure CL (CCL)
- Originalmente um fork gratuito e de código aberto do Macintosh Common Lisp. Como essa história indica, o CCL foi escrito para Macintosh, mas o Clozure CL agora roda em macOS , FreeBSD , Linux , Solaris e Windows . Portas x86 de 32 e 64 bits são suportadas em cada plataforma. Além disso, existem portas Power PC para Mac OS e Linux. CCL era conhecido anteriormente como OpenMCL, mas esse nome não é mais usado, para evitar confusão com a versão de código aberto do Macintosh Common Lisp.
- CMUCL
- Originalmente da Carnegie Mellon University , agora mantido como software livre e de código aberto por um grupo de voluntários. CMUCL usa um compilador de código nativo rápido. Ele está disponível em Linux e BSD para Intel x86; Linux para Alpha; macOS para Intel x86 e PowerPC; e Solaris, IRIX e HP-UX em suas plataformas nativas.
- Corman Common Lisp
- para Microsoft Windows. Em janeiro de 2015, Corman Lisp foi publicado sob a licença do MIT.
- Lisp comum incorporável (ECL)
- ECL inclui um interpretador e compilador de bytecode. Ele também pode compilar código Lisp para código de máquina por meio de um compilador C. ECL então compila o código Lisp para C, compila o código C com um compilador C e pode então carregar o código de máquina resultante. Também é possível ECL incorporar em C programas e código C em programas Lisp Comum.
- GNU Common Lisp (GCL)
- O compilador Lisp do Projeto GNU . Ainda não totalmente compatível com ANSI, GCL é, no entanto, a implementação preferida para vários grandes projetos, incluindo as ferramentas matemáticas Maxima , AXIOM e (historicamente) ACL2 . O GCL é executado no Linux em onze arquiteturas diferentes e também no Windows, Solaris e FreeBSD .
- Macintosh Common Lisp (MCL)
- A versão 5.2 para computadores Apple Macintosh com um processador PowerPC executando Mac OS X é de código aberto. RMCL (baseado em MCL 5.2) é executado em computadores Apple Macintosh baseados em Intel usando o conversor binário Rosetta da Apple.
- ManKai Common Lisp (MKCL)
- Uma filial da ECL . O MKCL enfatiza a confiabilidade, estabilidade e qualidade geral do código por meio de um sistema de tempo de execução altamente retrabalhado e multi-threaded nativo. No Linux, o MKCL apresenta um sistema de tempo de execução totalmente compatível com POSIX.
- Movitz
- Implementa um ambiente Lisp para computadores x86 sem depender de nenhum sistema operacional subjacente.
- Poplog
- Poplog implementa uma versão do CL, com POP-11 , e opcionalmente Prolog e Standard ML (SML), permitindo a programação em linguagem mista. Para todos, a linguagem de implementação é POP-11, que é compilado de forma incremental. Ele também possui um editor semelhante ao Emacs integrado que se comunica com o compilador.
- Steel Bank Common Lisp (SBCL)
- Uma filial da CMUCL . "Em termos gerais, o SBCL se distingue do CMU CL por uma maior ênfase na capacidade de manutenção." SBCL roda nas plataformas CMUCL, exceto HP / UX; além disso, ele roda em Linux para AMD64, PowerPC, SPARC, MIPS, Windows x86 e tem suporte experimental para rodar em Windows AMD64. SBCL não usa um intérprete por padrão; todas as expressões são compiladas em código nativo, a menos que o usuário ative o interpretador. O compilador SBCL gera código nativo rápido de acordo com uma versão anterior do The Computer Language Benchmarks Game .
- Ufasoft Common Lisp
- porta do CLISP para a plataforma Windows com núcleo escrito em C ++.
Outras implementações
- Austin Kyoto Common Lisp
- uma evolução do Kyoto Common Lisp por Bill Schelter
- Butterfly Common Lisp
- uma implementação escrita em Scheme para o computador multiprocessador BBN Butterfly
- CLICC
- um compilador Common Lisp para C
- CLOE
- Lisp comum para PCs da Symbolics
- Codemist Common Lisp
- usado para a versão comercial do sistema de álgebra computacional Axiom
- ExperCommon Lisp
- uma implementação inicial para o Apple Macintosh por ExperTelligence
- Golden Common Lisp
- uma implementação para PC pela GoldHill Inc.
- Ibuki Common Lisp
- uma versão comercializada do Kyoto Common Lisp
- Kyoto Common Lisp
- o primeiro compilador Common Lisp que usou C como linguagem de destino. GCL, ECL e MKCL originam-se dessa implementação do Common Lisp.
- eu
- uma pequena versão do Common Lisp para sistemas embarcados desenvolvido pela IS Robotics, agora iRobot
- Máquinas Lisp (da Symbolics , TI e Xerox)
- forneceu implementações de Common Lisp além de seu dialeto Lisp nativo (Lisp Machine Lisp ou Interlisp). CLOS também estava disponível. O Symbolics fornece uma versão aprimorada do Common Lisp.
- Procyon Common Lisp
- uma implementação para Windows e Mac OS, usada por Franz para sua porta do Windows do Allegro CL
- Star Sapphire Common LISP
- uma implementação para o PC
- SubL
- uma variante do Common Lisp usado para a implementação do sistema baseado em conhecimento Cyc
- Lisp comum de nível superior
- uma implementação inicial para execução simultânea
- WCL
- uma implementação de biblioteca compartilhada
- VAX Common Lisp
- Implementação da Digital Equipment Corporation que foi executada em sistemas VAX executando VMS ou ULTRIX
- XLISP
- uma implementação escrita por David Betz
Formulários
Common Lisp é usado para desenvolver aplicativos de pesquisa (geralmente em Inteligência Artificial ), para desenvolvimento rápido de protótipos ou para aplicativos implantados.
Common Lisp é usado em muitos aplicativos comerciais, incluindo o Yahoo! Site de comércio na web da loja, que originalmente envolvia Paul Graham e mais tarde foi reescrito em C ++ e Perl . Outros exemplos notáveis incluem:
- ACT-R , uma arquitetura cognitiva usada em um grande número de projetos de pesquisa.
- Authorizer Assistant, um grande sistema baseado em regras usado pela American Express, que analisa solicitações de crédito.
- Cyc , um projeto de longa duração para criar um sistema baseado em conhecimento que fornece uma grande quantidade de conhecimento de senso comum.
- Gensym G2 , um sistema especialista em tempo real e mecanismo de regras de negócios
- Genworks GDL, baseado no kernel Gendl de código aberto.
- O ambiente de desenvolvimento para a série de videogames Jak and Daxter , desenvolvido pela Naughty Dog .
- O mecanismo de busca de baixa tarifa da ITA Software , usado por sites de viagens como Orbitz e Kayak.com e companhias aéreas como American Airlines , Continental Airlines e US Airways .
- Mirai , uma suíte gráfica 3D. Foi usado para animar o rosto de Gollum no filme O Senhor dos Anéis: As Duas Torres .
- Opusmodus é um sistema de composição musical baseado em Common Lisp, utilizado na composição assistida por computador .
- Prototype Verification System (PVS), um ambiente mecanizado para especificação e verificação formal.
- PWGL é um ambiente de programação visual sofisticado baseado em Common Lisp, usado em composição assistida por computador e síntese de som.
- Piano, um pacote completo de análise de aeronaves, escrito em Common Lisp, usado por empresas como Boeing , Airbus e Northrop Grumman .
- Grammarly , uma plataforma de aprimoramento da escrita no idioma inglês, tem seu mecanismo de gramática principal escrito em Common Lisp.
- A ferramenta de análise dinâmica e replanejamento (DART), que, segundo se diz, foi a única a pagar durante os anos de 1991 a 1995 por todos os trinta anos de investimentos da DARPA em pesquisa de IA.
- NASA 's Jet Propulsion Lab ' s " Deep Space 1 ", um programa Lisp Comum premiado para autopiloting o Deep Space Uma nave espacial.
- SigLab, uma plataforma Common Lisp para processamento de sinais usada em defesa antimísseis, construída pela Raytheon .
- Mars Pathfinder Mission Planning System da NASA .
- SPIKE, um sistema de programação para observatórios e satélites baseados na Terra ou no espaço, notavelmente o Telescópio Espacial Hubble, escrito em Common Lisp.
- Common Lisp foi usado para criar um protótipo do coletor de lixo do .NET Common Language Runtime da Microsoft .
- A versão original do Reddit , embora os desenvolvedores mais tarde tenham mudado para o Python devido à falta de bibliotecas para Common Lisp, de acordo com uma postagem no blog oficial do co-fundador do Reddit Steve Huffman .
Também existem aplicativos de código aberto escritos em Common Lisp, como:
- ACL2 , um provador de teoremas automatizado com recursos completos para uma variante de aplicativo do Common Lisp.
- Axiom , um sofisticado sistema de álgebra computacional .
- Maxima , um sofisticado sistema de álgebra computacional , baseado em Macsyma.
- OpenMusic , um ambiente de programação visual orientado a objetos baseado em Common Lisp, usado em composição assistida por computador .
- Pgloader, um carregador de dados para PostgreSQL , que foi reescrito de Python para Common Lisp.
- Stumpwm , um gerenciador de janelas X11 controlado por teclado e ladrilhado, escrito inteiramente em Common Lisp.
Veja também
Referências
Bibliografia
Uma lista cronológica de livros publicados (ou em vias de publicação) sobre Common Lisp (a linguagem) ou sobre programação com Common Lisp (especialmente programação AI).
- Guy L. Steele : Common Lisp the Language, 1ª edição , Digital Press, 1984, ISBN 0-932376-41-X
- Rodney Allen Brooks : Programming in Common Lisp , John Wiley and Sons Inc, 1985, ISBN 0-471-81888-7
- Richard P. Gabriel : Performance and Evaluation of Lisp Systems , The MIT Press, 1985, ISBN 0-262-57193-5 , PDF
- Robert Wilensky : Common LISPcraft , WW Norton & Co., 1986, ISBN 0-393-95544-3
- Eugene Charniak , Christopher K. Riesbeck , Drew V. McDermott , James R. Meehan : Artificial Intelligence Programming, 2ª edição , Lawrence Erlbaum, 1987, ISBN 0-89859-609-2
- Wendy L. Milner : Common Lisp: A Tutorial , Prentice Hall, 1987, ISBN 0-13-152844-0
- Deborah G. Tatar : A Programmer's Guide to Common Lisp , Longman Higher Education, 1987, ISBN 0-13-728940-5
- Taiichi Yuasa , Masami Hagiya : Introduction to Common Lisp , Elsevier Ltd, 1987, ISBN 0-12-774860-1
- Christian Queinnec , Jerome Chailloux : Lisp Evolution and Standardization , Ios Pr Inc., 1988, ISBN 90-5199-008-1
- Taiichi Yuasa , Richard Weyhrauch , Yasuko Kitajima : Common Lisp Drill , Academic Press Inc, 1988, ISBN 0-12-774861-X
- Wade L. Hennessey : Common Lisp , McGraw-Hill Inc., 1989, ISBN 0-07-028177-7
- Tony Hasemer , John Dominque : Common Lisp Programming for Artificial Intelligence , Addison-Wesley Educational Publishers Inc, 1989, ISBN 0-201-17579-7
- Sonya E. Keene : Programação Orientada a Objetos em Common Lisp: A Programmer's Guide to CLOS , Addison-Wesley, 1989, ISBN 0-201-17589-4
- David Jay Steele : Golden Common Lisp: A Hands-On Approach , Addison Wesley, 1989, ISBN 0-201-41653-0
- David S. Touretzky : Common Lisp: A Gentle Introduction to Symbolic Computation , Benjamin-Cummings, 1989, ISBN 0-8053-0492-4 . Reimpressão Web / PDF Dover (2013) ISBN 978-0486498201
- Christopher K. Riesbeck , Roger C. Schank : Inside Case-Based Reasoning , Lawrence Erlbaum, 1989, ISBN 0-89859-767-6
- Patrick Winston , Berthold Horn : Lisp, 3ª edição , Addison-Wesley, 1989, ISBN 0-201-08319-1 , Web
- Gerard Gazdar , Chris Mellish : Natural Language Processing in LISP: An Introduction to Computational Linguistics , Addison-Wesley Longman Publishing Co., 1990, ISBN 0-201-17825-7
- Patrick R. Harrison : Common Lisp and Artificial Intelligence , Prentice Hall PTR, 1990, ISBN 0-13-155243-0
- Timothy Koschmann : The Common Lisp Companion , John Wiley & Sons, 1990, ISBN 0-471-50308-8
- W. Richard Stark : LISP, Lore e Logic , Springer Verlag New York Inc., 1990, ISBN 978-0-387-97072-1 , PDF
- Molly M. Miller , Eric Benson : Lisp Style & Design , Digital Press, 1990, ISBN 1-55558-044-0
- Guy L. Steele : Common Lisp the Language , 2ª edição , Digital Press, 1990, ISBN 1-55558-041-6 , Web
- Robin Jones, Clive Maynard , Ian Stewart: The Art of Lisp Programming , Springer Verlag New York Inc., 1990, ISBN 978-3-540-19568-9 , PDF
- Steven L. Tanimoto : The Elements of Artificial Intelligence Using Common Lisp , Computer Science Press, 1990, ISBN 0-7167-8230-8
- Peter Lee : Topics in Advanced Language Implementation , The MIT Press, 1991, ISBN 0-262-12151-4
- John H. Riley : A Common Lisp Workbook , Prentice Hall, 1991, ISBN 0-13-155797-1
- Peter Norvig : Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp , Morgan Kaufmann, 1991, ISBN 1-55860-191-0 , Web
- Gregor Kiczales , Jim des Rivieres , Daniel G. Bobrow : The Art of the Metaobject Protocol , The MIT Press, 1991, ISBN 0-262-61074-4
- Jo A. Lawless , Molly M. Miller : Understanding CLOS: The Common Lisp Object System , Digital Press, 1991, ISBN 0-13-717232-X
- Mark Watson: Common Lisp Modules: Artificial Intelligence in the Era of Neural Networks and Chaos Theory , Springer Verlag New York Inc., 1991, ISBN 0-387-97614-0 , PDF
- James L. Noyes : Artificial Intelligence with Common Lisp: Fundamentals of Symbolic and Numeric Processing , Jones & Bartlett Pub, 1992, ISBN 0-669-19473-5
- Stuart C. Shapiro : COMMON LISP: An Interactive Approach , Computer Science Press, 1992, ISBN 0-7167-8218-9 , Web / PDF
- Kenneth D. Forbus , Johan de Kleer : Building Problem Solvers , The MIT Press, 1993, ISBN 0-262-06157-0
- Andreas Paepcke : Programação Orientada a Objetos: The CLOS Perspective , The MIT Press, 1993, ISBN 0-262-16136-2
- Paul Graham : On Lisp , Prentice Hall, 1993, ISBN 0-13-030552-9 , Web / PDF
- Paul Graham : ANSI Common Lisp , Prentice Hall, 1995, ISBN 0-13-370875-6
- Otto Mayer : Programmieren in Common Lisp , German, Spektrum Akademischer Verlag, 1995, ISBN 3-86025-710-2
- Stephen Slade : Object-Oriented Common Lisp , Prentice Hall, 1997, ISBN 0-13-605940-6
- Richard P. Gabriel : Patterns of Software: Tales from the Software Community , Oxford University Press, 1998, ISBN 0-19-512123-6 , PDF
- Taiichi Yuasa , Hiroshi G. Okuno : Advanced Lisp Technology , CRC, 2002, ISBN 0-415-29819-9
- David B. Lamkins : Success Lisp: How to Understand and Use Common Lisp , bookfix.com, 2004. ISBN 3-937526-00-5 , Web
- Peter Seibel : Practical Common Lisp , Apress, 2005. ISBN 1-59059-239-5 , Web
- Doug Hoyte : Let Over Lambda , Lulu.com, 2008, ISBN 1-4357-1275-7 , Web
- George F. Luger , William A. Stubblefield : AI Algorithms, Data Structures, and Idioms in Prolog, Lisp e Java , Addison Wesley, 2008, ISBN 0-13-607047-7 , PDF
- Conrad Barski : Land of Lisp: Aprenda a programar em Lisp, um jogo de cada vez! , No Starch Press, 2010, ISBN 1-59327-200-6 , Web
- Pavel Penev : Lisp Web Tales , Leanpub, 2013, Web
- Edmund Weitz : Common Lisp Recipes , Apress, 2015, ISBN 978-1-484211-77-9 , Web
- Patrick M. Krusenotto : Funktionale Programmierung und Metaprogrammierung, Interaktiv in Common Lisp , Springer Fachmedien Wiesbaden 2016, ISBN 978-3-658-13743-4 , Web
links externos
- Quicklisp - Um gerenciador de biblioteca muito popular e de alta qualidade para Common Lisp
- The Awesome CL list, uma lista com curadoria de frameworks e bibliotecas Common Lisp.
- The Common Lisp Cookbook , um projeto colaborativo.
- O CLiki , um Wiki para sistemas Common Lisp gratuitos e de código aberto rodando em sistemas do tipo Unix.
- Um dos principais repositórios de Common Lisp gratuito para software é Common-Lisp.net .
- lisp-lang.org tem documentação e uma vitrine de histórias de sucesso.
- Uma visão geral da história do Common Lisp: "História" . Common Lisp HyperSpec .
- Referência rápida do Common Lisp - uma visão geral compacta da linguagem padrão do Common Lisp.
- Planet Lisp Artigos sobre Common Lisp.
- Quickdocs resume a documentação e informações de dependência para muitos projetos Quicklisp.