Lisp (linguagem de programação)
Lisp (historicamente LISP, um acrônimo para list pprocessamento) é uma família de linguagens de programação com uma longa história e uma notação de prefixo distinta e totalmente entre parênteses. Originalmente especificada em 1960, Lisp é a segunda linguagem de programação de alto nível mais antiga ainda em uso comum, depois de Fortran. Lisp mudou desde seus primeiros dias, e muitos dialetos existiram ao longo de sua história. Hoje, os dialetos Lisp de uso geral mais conhecidos são Common Lisp, Scheme, Racket e Clojure.
Lisp foi originalmente criado como uma notação matemática prática para programas de computador, influenciado (embora não originalmente derivado) da notação do cálculo lambda de Alonzo Church. Rapidamente se tornou uma linguagem de programação favorita para pesquisa de inteligência artificial (IA). Como uma das primeiras linguagens de programação, Lisp foi pioneira em muitas ideias em ciência da computação, incluindo estruturas de dados em árvore, gerenciamento automático de armazenamento, tipagem dinâmica, condicionais, funções de ordem superior, recursão, compilador auto-hospedado e read-eval-print laço.
O nome LISP deriva de "LIST Processor". As listas vinculadas são uma das principais estruturas de dados do Lisp, e o código-fonte do Lisp é feito de listas. Assim, os programas Lisp podem manipular o código-fonte como uma estrutura de dados, dando origem aos sistemas de macro que permitem aos programadores criar nova sintaxe ou novas linguagens específicas de domínio incorporadas ao Lisp.
A permutabilidade de código e dados dá ao Lisp sua sintaxe instantaneamente reconhecível. Todo o código do programa é escrito como s-expressões ou listas entre parênteses. Uma chamada de função ou forma sintática é escrita como uma lista com o nome da função ou do operador primeiro e os argumentos a seguir; por exemplo, uma função f
que recebe três argumentos seria chamado como (f arg1 arg2 arg3)
.
História
John McCarthy começou a desenvolver o Lisp em 1958 enquanto trabalhava no Massachusetts Institute of Technology (MIT). McCarthy publicou seu projeto em um artigo na Communications of the ACM em abril de 1960, intitulado "Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I". Ele mostrou que com alguns operadores simples e uma notação para funções anônimas emprestadas de Church, pode-se construir uma linguagem Turing-completa para algoritmos.
A Information Processing Language foi a primeira linguagem de IA, de 1955 ou 1956, e já incluía muitos dos conceitos, como processamento de listas e recursão, que passaram a ser usados no Lisp.
A notação original de McCarthy usava "M-expressões" que seria traduzido em S-expressões. Como exemplo, a expressão M car[cons[A,B ]]
é equivalente à expressão S (carro (contras A B))
. Depois que o Lisp foi implementado, os programadores rapidamente optaram por usar expressões S e as expressões M foram abandonadas. As expressões M surgiram novamente com tentativas de curta duração de MLisp por Horace Enea e CGOL por Vaughan Pratt.
Lisp foi implementado pela primeira vez por Steve Russell em um computador IBM 704 usando cartões perfurados. Russell leu o artigo de McCarthy e percebeu (para surpresa de McCarthy) que a função Lisp eval poderia ser implementada em código de máquina.
De acordo com McCarthy:
Steve Russell disse, olha, porque não programa isto? eval... e eu disse-lhe, ho, ho, tu estás a confundir a teoria com a prática, isto eval é destinado a leitura, não para computação. Mas ele foi em frente e fê-lo. Ou seja, ele compilou o eval em meu papel no código de máquina IBM 704, fixando bugs e, em seguida, anunciou isso como um intérprete Lisp, que certamente foi. Então nesse ponto Lisp tinha essencialmente a forma que tem hoje...
O resultado foi um interpretador Lisp funcional que pode ser usado para executar programas Lisp ou, mais apropriadamente, "avaliar expressões Lisp".
Duas macros em linguagem assembly para o IBM 704 tornaram-se as operações primitivas para a decomposição de listas: car (Conteúdo da parte Endereço do Número do Registro) e cdr (Conteúdo da parte do Decremento do Registro número), onde "registrar" refere-se aos registros da unidade central de processamento (CPU) do computador. Os dialetos Lisp ainda usam car
e cdr
(e) para as operações que retornar o primeiro item em uma lista e o resto da lista, respectivamente.
O primeiro compilador Lisp completo, escrito em Lisp, foi implementado em 1962 por Tim Hart e Mike Levin no MIT, e poderia ser compilado simplesmente tendo um interpretador LISP existente interpretando o código do compilador, produzindo uma saída de código de máquina capaz de ser executada com uma melhoria de 40 vezes na velocidade em relação à do intérprete. Este compilador introduziu o modelo Lisp de compilação incremental, no qual as funções compiladas e interpretadas podem se misturar livremente. A linguagem usada no memorando de Hart e Levin é muito mais próxima do estilo Lisp moderno do que o código anterior de McCarthy.
As rotinas de coleta de lixo foram desenvolvidas pelo aluno de pós-graduação do MIT, Daniel Edwards, antes de 1962.
Durante as décadas de 1980 e 1990, um grande esforço foi feito para unificar o trabalho em novos dialetos Lisp (principalmente sucessores do Maclisp, como ZetaLisp e NIL (Nova Implementação de Lisp) em um único idioma. O novo idioma, Common Lisp, era um pouco compatível com os dialetos que substituiu (o livro Common Lisp the Language observa a compatibilidade de várias construções). Em 1994, ANSI publicou o padrão Common Lisp, "ANSI X3.226-1994 Linguagem de programação de tecnologia da informação Common Lisp".
Cronograma
1955 | 1960 | 1965 | 1970 | 1975 | 1980 | 1985 | 1990 | 1995 | 2000 | 2005 | 2010 | 2015 | 2020 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
LISP 1, 1.5, LISP 2 (abandonado) | ||||||||||||||
Maclisp | ||||||||||||||
Interlisação | ||||||||||||||
MDL | ||||||||||||||
Máquina de Lisp | ||||||||||||||
Esquema | R5RS | R6RS | R7RS pequeno | |||||||||||
NIL | ||||||||||||||
ZIL (Língua de Implementação de Zork) | ||||||||||||||
Franz Lisp | ||||||||||||||
Lisp comum | Padrão ANSI | |||||||||||||
Le Lisp | ||||||||||||||
MIT Esquema | ||||||||||||||
T | ||||||||||||||
Chez Scheme | ||||||||||||||
Emacs Lisp | ||||||||||||||
AutoLISP | ||||||||||||||
Pico Lisp | ||||||||||||||
Gambito | ||||||||||||||
Eu... | ||||||||||||||
ISLISP | ||||||||||||||
Abre a porta. | ||||||||||||||
PLT Esquema | Racket | |||||||||||||
GNU Guile | ||||||||||||||
Visual LISP | ||||||||||||||
Clojure | ||||||||||||||
Arco | ||||||||||||||
LFE | ||||||||||||||
Hy |
Conexão com inteligência artificial
Desde o início, Lisp esteve intimamente conectado com a comunidade de pesquisa de inteligência artificial, especialmente em sistemas PDP-10. Lisp foi usado como a implementação da linguagem Micro Planner, que foi usada no famoso sistema de IA SHRDLU. Na década de 1970, quando a pesquisa de IA gerou ramificações comerciais, o desempenho dos sistemas Lisp existentes tornou-se um problema crescente, pois os programadores precisavam estar familiarizados com as ramificações de desempenho das várias técnicas e escolhas envolvidas na implementação do Lisp.
Genealogia e variantes
Ao longo de seus sessenta anos de história, Lisp gerou muitas variações sobre o tema central de uma linguagem S-expression. Além disso, cada dialeto dado pode ter várias implementações - por exemplo, há mais de uma dúzia de implementações de Common Lisp.
As diferenças entre os dialetos podem ser bastante visíveis—por exemplo, Common Lisp usa a palavra-chave defun
para nomear uma função, mas Scheme usa define
. Dentro de um dialeto que é padronizado, no entanto, as implementações em conformidade suportam o mesmo idioma principal, mas com diferentes extensões e bibliotecas.
Dialetos historicamente significativos
- LISP 1 – Primeira implementação.
- LISP 1.5 – Primeira versão amplamente distribuída, desenvolvida por McCarthy e outros no MIT. Então nomeado porque continha várias melhorias no interpretador original "LISP 1", mas não era uma grande reestruturação como o LISP 2 planejado seria.
- Stanford LISP 1.6 – Este foi um sucessor do LISP 1.5 desenvolvido no Stanford AI Lab, e amplamente distribuído para sistemas PDP-10 com o sistema operacional TOPS-10. Foi tornado obsoleto por Maclisp e InterLisp.
- MACLISP – desenvolvido para o projeto MAC do MIT, MACLISP é um descendente direto do LISP 1.5. Correu nos sistemas PDP-10 e Multics. MACLISP mais tarde viria a ser chamado Maclisp, e é frequentemente referido como MacLisp. O "MAC" no MACLISP está relacionado nem ao Macintosh da Apple nem ao McCarthy.
- Interlisp – desenvolvido na BBN Technologies para sistemas PDP-10 que executam o sistema operacional TENEX, mais tarde adotado como um Lisp "West Coast" para as máquinas Xerox Lisp como InterLisp-D. Uma versão pequena chamada "InterLISP 65" foi publicada para a linha de computadores da família Atari 8 bits, de 6502. Durante algum tempo, Maclisp e InterLisp foram fortes concorrentes.
- Franz Lisp – originalmente um projeto da Universidade da Califórnia em Berkeley; mais tarde desenvolvido pela Franz Inc. O nome é uma deformação humorística do nome "Franz Liszt", e não se refere a Allegro Common Lisp, o dialeto de Common Lisp vendido por Franz Inc., nos últimos anos.
- XLISP, em que o AutoLISP foi baseado.
- Lisp padrão e Lisp padrão portátil foram amplamente utilizados e portados, especialmente com o REDUCE do Sistema de Álgebra de Computador.
- ZetaLisp, também chamado Lisp Machine Lisp – usado nas máquinas Lisp, descendente direto de Maclisp. ZetaLisp teve uma grande influência sobre o Lisp Comum.
- LeLisp é um dialeto francês Lisp. Um dos primeiros construtores de interface (chamados SOS Interface) foi escrito em LeLisp.
- Scheme (1975).
- Lisp Comum (1984), conforme descrito por Lisp comum a língua – uma consolidação de várias tentativas divergentes (ZetaLisp, Spice Lisp, NIL e S-1 Lisp) para criar dialetos sucessores para Maclisp, com influências substanciais do dialeto Scheme também. Esta versão do Common Lisp estava disponível para plataformas amplas e foi aceita por muitos como um padrão de facto até a publicação da ANSI Common Lisp (ANSI X3.226-1994). Entre as subdivisões mais comuns do Common Lisp estão o Steel Bank Common Lisp (SBCL), CMU Common Lisp (CMU-CL), Clozure OpenMCL (para não ser confundido com Clojure!), GNU CLisp, e versões posteriores de Franz Lisp; todos eles aderem ao mais recente padrão ANSI CL (veja abaixo).
- Dylan foi em sua primeira versão uma mistura de Scheme com o Common Lisp Object System.
- EuLisp – tentativa de desenvolver um novo Lisp eficiente e limpo.
- ISLISP – tentativa de desenvolver um novo Lisp eficiente e limpo. Normalizado como ISO/IEC 13816:1997 e posteriormente revisado como ISO/IEC 13816:2007: Tecnologia da informação – Linguagens de programação, seus ambientes e interfaces de software do sistema – Linguagem de programação ISLISP.
- IEEE Scheme – padrão IEEE, 1178–1990 (R1995).
- ANSI Common Lisp – um padrão do American National Standards Institute (ANSI) para o Common Lisp, criado pelo subcomité X3J13, fretado para começar Lisp comum: A língua como um documento base e trabalhar através de um processo de consenso público para encontrar soluções para questões compartilhadas de portabilidade de programas e compatibilidade de implementações do Common Lisp. Embora formalmente um padrão ANSI, a implementação, venda, uso e influência da ANSI Common Lisp tem sido e continua a ser vista em todo o mundo.
- ACL2 ou "A Computational Logic for Applicative Common Lisp", uma variante aplicativa (livre de efeitos colaterais) do Common LISP. ACL2 é uma linguagem de programação que pode modelar sistemas de computador e uma ferramenta para ajudar a provar propriedades desses modelos.
- Clojure, um dialeto recente de Lisp que compila para a máquina virtual Java e tem um foco particular em concurrency.
- Game Oriented Assembly Lisp (ou GOAL) é uma linguagem de programação de jogos eletrônico desenvolvida por Andy Gavin no Naughty Dog. Foi escrito usando Allegro Common Lisp e usado no desenvolvimento de toda a série Jak e Daxter de jogos desenvolvidos por Naughty Dog.
2000 até o presente
Depois de ter diminuído um pouco na década de 1990, Lisp experimentou um ressurgimento de interesse após 2000. A maioria das novas atividades tem se concentrado em implementações de Common Lisp, Scheme, Emacs Lisp, Clojure e Racket, e inclui o desenvolvimento de novas bibliotecas portáteis e aplicações.
Muitos novos programadores Lisp foram inspirados por escritores como Paul Graham e Eric S. Raymond para buscar uma linguagem que outros consideravam antiquada. Novos programadores Lisp geralmente descrevem a linguagem como uma experiência reveladora e afirmam ser substancialmente mais produtivos do que em outras linguagens. Esse aumento na conscientização pode ser comparado ao "inverno AI" e o breve ganho de Lisp em meados da década de 1990.
Em 2010, havia onze implementações Common Lisp mantidas ativamente. Scieneer Common Lisp é uma nova implementação comercial bifurcada da CMUCL com um primeiro lançamento em 2002.
A comunidade de código aberto criou uma nova infraestrutura de suporte: CLiki é um wiki que coleta informações relacionadas ao Common Lisp, o diretório Common Lisp lista recursos, #lisp é um canal IRC popular e permite o compartilhamento e comentários de trechos de código (com suporte por lisppaste, um bot de IRC escrito em Lisp), Planet Lisp coleta o conteúdo de vários blogs relacionados a Lisp, no LispForum usuários discutem tópicos Lisp, Lispjobs é um serviço para anunciar ofertas de emprego e há um serviço de notícias semanal, Semanalmente Lisp News. Common-lisp.net é um site de hospedagem para projetos Common Lisp de código aberto. Quicklisp é um gerenciador de biblioteca para Common Lisp.
Cinquenta anos de Lisp (1958–2008) foram comemorados no LISP50@OOPSLA. Há reuniões regulares de usuários locais em Boston, Vancouver e Hamburgo. Outros eventos incluem o European Common Lisp Meeting, o European Lisp Symposium e uma International Lisp Conference.
A comunidade Scheme mantém ativamente mais de vinte implementações. Várias novas implementações significativas (Chicken, Gambit, Gauche, Ikarus, Larceny, Ypsilon) foram desenvolvidas nos anos 2000 (década). O Relatório5 Revisado sobre o padrão Algorithmic Language Scheme de Scheme foi amplamente aceito na comunidade Scheme. O processo de Solicitações de Implementação do Scheme criou muitas bibliotecas e extensões quase padrão para o Scheme. As comunidades de usuários de implementações individuais do Esquema continuam a crescer. Um novo processo de padronização de linguagem foi iniciado em 2003 e levou ao padrão R6RS Scheme em 2007. O uso acadêmico do Scheme para o ensino de ciência da computação parece ter diminuído um pouco. Algumas universidades não estão mais usando o Scheme em seus cursos introdutórios de ciência da computação; O MIT agora usa Python em vez de Scheme para seu programa de graduação em ciência da computação e o curso online aberto massivo do MITx.
Existem vários novos dialetos de Lisp: Arc, Hy, Nu, Liskell e LFE (Lisp Flavored Erlang). O parser para Julia é implementado em Femtolisp, um dialeto de Scheme (Julia é inspirado por Scheme, que por sua vez é um dialeto de Lisp).
Em outubro de 2019, Paul Graham lançou uma especificação para Bel, "um novo dialeto de Lisp."
Principais dialetos
Common Lisp e Scheme representam dois fluxos principais de desenvolvimento de Lisp. Essas linguagens incorporam opções de design significativamente diferentes.
Common Lisp é um sucessor do Maclisp. As principais influências foram Lisp Machine Lisp, Maclisp, NIL, S-1 Lisp, Spice Lisp e Scheme. Ele tem muitos dos recursos do Lisp Machine Lisp (um grande dialeto Lisp usado para programar Lisp Machines), mas foi projetado para ser implementado com eficiência em qualquer computador pessoal ou estação de trabalho. Common Lisp é uma linguagem de programação de uso geral e, portanto, possui um grande padrão de linguagem, incluindo muitos tipos de dados integrados, funções, macros e outros elementos de linguagem e um sistema de objetos (Common Lisp Object System). O Common Lisp também emprestou certos recursos do Scheme, como escopo léxico e fechamentos léxicos. Implementações comuns de Lisp estão disponíveis para segmentar diferentes plataformas, como LLVM, Java virtual machine, x86-64, PowerPC, Alpha, ARM, Motorola 68000 e MIPS, e sistemas operacionais como Windows, macOS, Linux, Solaris, FreeBSD, NetBSD, OpenBSD, Dragonfly BSD e Heroku.
Scheme é um dialeto com escopo estático e recursivo de cauda da linguagem de programação Lisp inventado por Guy L. Steele, Jr. e Gerald Jay Sussman. Ele foi projetado para ter uma semântica excepcionalmente clara e simples e poucas maneiras diferentes de formar expressões. Projetado cerca de uma década antes do Common Lisp, Scheme é um design mais minimalista. Ele tem um conjunto muito menor de recursos padrão, mas com certos recursos de implementação (como otimização de chamada final e continuações completas) não especificados em Common Lisp. Uma ampla variedade de paradigmas de programação, incluindo estilos imperativos, funcionais e de passagem de mensagens, encontra expressão conveniente em Scheme. O esquema continua a evoluir com uma série de padrões (relatório n revisado sobre o esquema de linguagem algorítmica) e uma série de solicitações de esquema para implementação.
Clojure é um dialeto recente de Lisp que visa principalmente a máquina virtual Java e o Common Language Runtime (CLR), o Python VM, o Ruby VM YARV e a compilação para JavaScript. Ele é projetado para ser uma linguagem pragmática de uso geral. Clojure extrai influências consideráveis de Haskell e coloca uma ênfase muito forte na imutabilidade. Clojure fornece acesso a estruturas e bibliotecas Java, com dicas de tipo opcionais e inferência de tipo, para que as chamadas para Java possam evitar reflexão e permitir operações primitivas rápidas. Clojure não foi projetado para ser compatível com outros dialetos Lisp.
Além disso, os dialetos Lisp são usados como linguagens de script em muitos aplicativos, sendo o mais conhecido Emacs Lisp no editor Emacs, AutoLISP e posteriormente Visual Lisp no AutoCAD, Nyquist no Audacity e Scheme no LilyPond. O pequeno tamanho potencial de um interpretador Scheme útil o torna particularmente popular para scripts embutidos. Os exemplos incluem SIOD e TinyScheme, ambos incorporados com sucesso no processador de imagem GIMP sob o nome genérico "Script-fu". LIBREP, um interpretador Lisp de John Harper originalmente baseado na linguagem Emacs Lisp, foi incorporado ao gerenciador de janelas Sawfish.
Dialetos padronizados
Lisp tem dialetos oficialmente padronizados: R6RS Scheme, R7RS Scheme, IEEE Scheme, ANSI Common Lisp e ISO ISLISP.
Inovações de linguagem
Paul Graham identifica nove aspectos importantes do Lisp que o distinguem de linguagens existentes como o Fortran:
- Condicionados não limitados a goto
- Funções de primeira classe
- Recursão
- Tratar variáveis uniformemente como ponteiros, deixando tipos para valores
- Coleção de lixo
- Programas feitos inteiramente de expressões sem declarações
- O tipo de dados do símbolo, distinto do tipo de dados da string
- Notação de código feito de árvores de símbolos (usando muitos parênteses)
- Língua completa disponível em tempo de carga, tempo de compilação e tempo de execução
Lisp foi a primeira linguagem em que a estrutura do código do programa é representada fiel e diretamente em uma estrutura de dados padrão—uma qualidade muito mais tarde chamada de "homoiconicidade". Assim, as funções Lisp podem ser manipuladas, alteradas ou mesmo criadas dentro de um programa Lisp sem manipulações de nível inferior. Isso geralmente é considerado uma das principais vantagens da linguagem no que diz respeito ao seu poder expressivo e torna a linguagem adequada para macros sintáticas e avaliação metacircular.
Uma condicional usando uma sintaxe if–then–else foi inventada por McCarthy para um programa de xadrez escrito em Fortran. Ele propôs sua inclusão no ALGOL, mas não fez parte da especificação do Algol 58. Para Lisp, McCarthy usou a estrutura cond mais geral. Algol 60 pegou if–then–else e o popularizou.
Lisp influenciou profundamente Alan Kay, o líder da equipe de pesquisa que desenvolveu Smalltalk na Xerox PARC; e, por sua vez, Lisp foi influenciado por Smalltalk, com dialetos posteriores adotando recursos de programação orientada a objetos (classes de herança, instâncias de encapsulamento, passagem de mensagens, etc.) na década de 1970. O sistema de objetos Flavors introduziu o conceito de herança múltipla e o mixin. O Common Lisp Object System fornece herança múltipla, multimétodos com despacho múltiplo e funções genéricas de primeira classe, gerando uma forma flexível e poderosa de despacho dinâmico. Ele serviu como modelo para muitos sistemas de objetos Lisp subsequentes (incluindo Scheme), que são frequentemente implementados por meio de um protocolo de metaobjeto, um design metacircular reflexivo no qual o sistema de objetos é definido em termos de si mesmo: Lisp era apenas a segunda linguagem depois de Smalltalk (e ainda é uma das poucas linguagens) a possuir tal sistema de metaobjetos. Muitos anos depois, Alan Kay sugeriu que, como resultado da confluência desses recursos, apenas Smalltalk e Lisp poderiam ser considerados sistemas de programação orientados a objetos adequadamente concebidos.
Lisp introduziu o conceito de coleta de lixo automática, na qual o sistema percorre o heap procurando por memória não utilizada. O progresso em algoritmos modernos e sofisticados de coleta de lixo, como coleta de lixo geracional, foi estimulado por seu uso em Lisp.
Edsger W. Dijkstra em sua palestra no Prêmio Turing de 1972 disse:
Com alguns princípios muito básicos em sua fundação, ele [LISP] mostrou uma estabilidade notável. Além disso, o LISP tem sido o portador para um número considerável de, em certo sentido, nossas aplicações de computador mais sofisticadas. O LISP foi descrito como "a maneira mais inteligente de usar mal um computador". Acho que essa descrição é um grande elogio porque transmite o pleno sabor da libertação: ajudou um número de nossos semelhantes mais talentosos a pensar pensamentos antes impossíveis.
Em grande parte por causa de seus requisitos de recursos em relação ao hardware de computação inicial (incluindo os primeiros microprocessadores), Lisp não se tornou tão popular fora da comunidade de IA quanto Fortran e a linguagem C descendente de ALGOL. Devido à sua adequação a aplicações complexas e dinâmicas, Lisp teve algum ressurgimento do interesse popular na década de 2010.
Sintaxe e semântica
- Nota: Os exemplos deste artigo são escritos no Common Lisp (embora a maioria também seja válida no Scheme).
Expressões simbólicas (expressões S)
Lisp é uma linguagem orientada a expressões. Ao contrário da maioria dos outros idiomas, nenhuma distinção é feita entre "expressões" e "declarações"; todos os códigos e dados são escritos como expressões. Quando uma expressão é avaliada, ela produz um valor (em Common Lisp, possivelmente vários valores), que podem então ser embutidos em outras expressões. Cada valor pode ser qualquer tipo de dados.
O artigo de 1958 de McCarthy introduziu dois tipos de sintaxe: Expressões simbólicas (S-expressions, sexps), que espelham a representação interna de código e dados; e Metaexpressões (M-expressões), que expressam funções de S-expressões. As expressões M nunca foram bem aceitas e quase todos os Lisps hoje usam expressões S para manipular código e dados.
O uso de parênteses é a diferença mais óbvia de Lisp em relação a outras famílias de linguagens de programação. Como resultado, os alunos há muito tempo dão apelidos de Lisp como Perdido em parênteses estúpidos ou Muitos parênteses supérfluos irritantes. No entanto, a sintaxe da expressão S também é responsável por grande parte do poder do Lisp: a sintaxe é simples e consistente, o que facilita a manipulação por computador. No entanto, a sintaxe do Lisp não se limita à notação tradicional de parênteses. Pode ser estendido para incluir notações alternativas. Por exemplo, XMLisp é uma extensão Common Lisp que emprega o protocolo metaobject para integrar expressões S com a Extensible Markup Language (XML).
A dependência de expressões dá grande flexibilidade à linguagem. Como as funções Lisp são escritas como listas, elas podem ser processadas exatamente como dados. Isso permite a fácil escrita de programas que manipulam outros programas (metaprogramação). Muitos dialetos Lisp exploram esse recurso usando sistemas de macro, o que permite a extensão da linguagem quase sem limites.
Listas
Uma lista Lisp é escrita com seus elementos separados por espaços em branco e entre parênteses. Por exemplo, (1 2 foo)
é uma lista cujos elementos são os três átomos 1
, 2
e foo. Esses valores são digitados implicitamente: eles são respectivamente dois números inteiros e um tipo de dados específico do Lisp chamado de "símbolo", e não precisam ser declarados como tal.
A lista vazia ()
também é representado como o átomo especial nil. Esta é a única entidade em Lisp que é um átomo e uma lista.
As expressões são escritas como listas, usando notação de prefixo. O primeiro elemento da lista é o nome de uma função, o nome de uma macro, uma expressão lambda ou o nome de um "operador especial" (Veja abaixo). O restante da lista são os argumentos. Por exemplo, a função lista
retorna seus argumentos como uma lista, então a expressão
(lista 1 2 (citação Foo)
avalia a lista (1 2 foo). A "cotação" antes do foo no exemplo anterior é um "operador especial" que retorna seu argumento sem avaliá-lo. Quaisquer expressões sem aspas são avaliadas recursivamente antes que a expressão envolvente seja avaliada. Por exemplo,
(lista 1 2 (lista 3 4)
avalia a lista (1 2 (3 4))
. Observe que o terceiro argumento é uma lista; as listas podem ser aninhadas.
Operadores
Os operadores aritméticos são tratados de forma semelhante. A expressão
(+ 1 2 3 4)
é avaliado como 10. O equivalente na notação infixa seria "1 + 2 + 3 + 4
".
Lisp não tem noção de operadores implementados em linguagens derivadas de Algol. Operadores aritméticos em Lisp são funções variádicas (ou n-árias), capazes de receber qualquer número de argumentos. Um estilo C '++' operador de incremento às vezes é implementado sob o nome incf
dando sintaxe
(incf x)
equivalente a (setq x (+ x 1))
, retornando o novo valor de x
.
"Operadores especiais" (às vezes chamados de "formulários especiais") fornecem a estrutura de controle de Lisp. Por exemplo, o operador especial if
leva três argumentos. Se o primeiro argumento for diferente de nil, ele será avaliado como o segundo argumento; caso contrário, avalia para o terceiro argumento. Assim, a expressão
(se n (lista 1 2 "foo") (lista 3 4 "bar")
avaliado para (3 4 "barra")
. Claro, isso seria mais útil se uma expressão não trivial tivesse sido substituída no lugar de nil
.
Lisp também fornece operadores lógicos and, or e not. Os operadores e e ou fazem avaliação de curto-circuito e retornarão seu primeiro argumento nulo e não nulo, respectivamente.
(ou (e "zero" n "nunca") "James" 'tarefa' Tempo)
avaliará para "James".
Expressões lambda e definição de função
Outro operador especial, lambda
, é usado para vincular variáveis a valores que são então avaliados dentro de uma expressão. Este operador também é usado para criar funções: os argumentos para lambda
são uma lista de argumentos e a expressão ou expressões para as quais a função é avaliada (o valor retornado é o valor da última expressão avaliada). A expressão
(Lambda (Arg) (+ Arg 1)
avalia uma função que, quando aplicada, recebe um argumento e o vincula a arg
e retorna o número um maior que esse argumento. As expressões lambda não são tratadas de maneira diferente das funções nomeadas; eles são invocados da mesma maneira. Portanto, a expressão
(Lambda (Arg) (+ Arg 1) 5)
avaliado para 6
. Aqui, estamos fazendo uma aplicação de função: executamos a função anônima passando para ela o valor 5.
As funções nomeadas são criadas armazenando uma expressão lambda em um símbolo usando a macro defun.
(defuntos Foo (um b) c D) (+ um b) c D)
(defun f (a) b...)
define uma nova função chamada f
no ambiente global. É conceitualmente semelhante à expressão:
(setf (fdefinição ") # '(Lambda (um) (bloco f b...)
onde setf
é um macro usada para definir o valor do primeiro argumento fdefinition 'f
para um novo objeto de função. fdefinition
é uma definição de função global para a função denominada f
. #'
é um abreviatura para função
operador especial, retornando um objeto de função.
Átomos
No LISP original havia dois tipos de dados fundamentais: átomos e listas. Uma lista era uma sequência ordenada finita de elementos, onde cada elemento é um átomo ou uma lista, e um átomo era um número ou um símbolo. Um símbolo era essencialmente um item nomeado exclusivo, escrito como uma string alfanumérica no código-fonte e usado como um nome de variável ou como um item de dados no processamento simbólico. Por exemplo, a lista (FOO (BAR 1) 2)
contém três elementos: o símbolo FOO
, a lista (BAR 1)
e o número 2.
A diferença essencial entre átomos e listas era que os átomos eram imutáveis e únicos. Dois átomos que apareciam em lugares diferentes no código-fonte, mas eram escritos exatamente da mesma maneira, representavam o mesmo objeto, enquanto cada lista era um objeto separado que podia ser alterado independentemente de outras listas e distinguido de outras listas por operadores de comparação.
Conforme mais tipos de dados foram introduzidos nos dialetos Lisp posteriores e os estilos de programação evoluíram, o conceito de átomo perdeu importância. Muitos dialetos ainda retêm o predicado átomo para compatibilidade herdada, definindo-o como verdadeiro para qualquer objeto que não seja um contras.
Conselhos e listas
Uma lista Lisp é implementada como uma lista encadeada individualmente. Cada célula desta lista é chamada de cons (em Scheme, um par) e é composta por dois ponteiros, chamados de car e cdr. Estes são respectivamente equivalentes aos dados
e próximo
discutidos no artigo lista encadeada.
Das muitas estruturas de dados que podem ser construídas a partir de células cons, uma das mais básicas é chamada de lista adequada. Uma lista adequada é o especial nil
(lista vazia), ou um contra no qual o carro
aponta para um dado (que pode ser outra estrutura cons, como uma lista) e o cdr
aponta para outra lista apropriada.
Se um determinado cons é considerado o cabeçalho de uma lista encadeada, então seu carro aponta para o primeiro elemento da lista e seu cdr aponta para o resto da lista. Por esse motivo, o carro
e As funções cdr
também são chamadas de primeiro
e rest
ao se referir a conses que fazem parte de uma lista vinculada (em vez do que, digamos, uma árvore).
Assim, uma lista Lisp não é um objeto atômico, como seria uma instância de uma classe container em C++ ou Java. Uma lista nada mais é do que um agregado de conses vinculados. Uma variável que se refere a uma determinada lista é simplesmente um ponteiro para os primeiros contras da lista. Percorrer uma lista pode ser feito cdring para baixo na lista; ou seja, levando cdrs sucessivos para visitar cada cons da lista; ou usando qualquer uma das várias funções de ordem superior para mapear uma função em uma lista.
Como conses e listas são tão universais em sistemas Lisp, é um equívoco comum pensar que eles são as únicas estruturas de dados de Lisp. Na verdade, todos, exceto os Lisp mais simplistas, têm outras estruturas de dados, como vetores (arrays), tabelas hash, estruturas e assim por diante.
S-expressões representam listas
As expressões S entre parênteses representam estruturas de lista vinculada. Existem várias maneiras de representar a mesma lista como uma expressão S. Um contra pode ser escrito em notação de par pontilhado como (a . b)
, onde a
é o carro e b
o cdr. Uma lista apropriada mais longa pode ser escrita (a . (b . (c . (d . nil))))
em notação de par pontilhado. Isso é abreviado convencionalmente como (a b c d)
em notação de lista. Uma lista imprópria pode ser escrita em uma combinação dos dois – como (a b c . d)
para a lista de três conses cujo último cdr é d
(ou seja, a lista (a . (b . (c . d)))
na forma totalmente especificada).
Procedimentos de processamento de lista
Lisp fornece muitos procedimentos integrados para acessar e controlar listas. As listas podem ser criadas diretamente com a lista
procedimento, que recebe qualquer número de argumentos e retorna a lista desses argumentos.
(lista 1 2 ' 3) ; Saída: (1 2 a 3)
(lista 1 '(2 3) 4) ; Saída (1 (2 3) 4)
Devido à maneira como as listas são construídas a partir de pares cons, o cons
pode ser usado para adicionar um elemento à frente de uma lista. Observe que o procedimento cons
é assimétrico em como ele lida com argumentos de lista, por causa de como as listas são construídas.
(Contras 1 '(2 3) ; Saída: (1 2 3)
(Contras '(1 2) '(3 4) ; Saída: ((1 2) 3 4)
O append
procedimento acrescenta duas (ou mais) listas uns aos outros. Como as listas Lisp são listas vinculadas, anexando duas listas tem complexidade de tempo assintotic O(n)O(n)}
(Anexo '(1 2) '(3 4) ; Saída: (1 2 3 4)
(Anexo '(1 2 3) '() '(um) '(5 6) ; Saída: (1 2 3 a 5 6)
Estrutura compartilhada
Listas Lisp, sendo listas encadeadas simples, podem compartilhar estrutura umas com as outras. Ou seja, duas listas podem ter a mesma cauda, ou sequência final de conses. Por exemplo, após a execução do seguinte código Common Lisp:
(setf Foo (lista ' B C)(setf bar (Contras "x" (cdr Foo)
as listas foo
e barra
são (a b c)
e (x b c)
respectivamente. No entanto, a cauda (b c)
é a mesma estrutura em ambas as listas. Não é uma cópia; as células contras apontando para b
e c
estão nos mesmos locais de memória para ambas as listas.
Compartilhar a estrutura em vez de copiar pode proporcionar uma melhoria drástica no desempenho. No entanto, essa técnica pode interagir de maneiras indesejadas com funções que alteram listas passadas a elas como argumentos. Alterar uma lista, como substituir o c
com um ganso
, afetará o outro:
(setf (terceiro Foo) "Goose")
Isso muda foo
para (a b ganso)
, mas também muda barra
para (x b ganso)
– um resultado possivelmente inesperado. Isso pode ser uma fonte de bugs, e as funções que alteram seus argumentos são documentadas como destrutivas por esse motivo.
Os aficionados da programação funcional evitam as funções destrutivas. No dialeto Scheme, que favorece o estilo funcional, os nomes das funções destrutivas são marcados com um ponto de exclamação de advertência, ou "bang"—como set-car!
(leia set car bang), que substitui o carro de um contras. No dialeto Common Lisp, as funções destrutivas são comuns; o equivalente a set-car!
é nomeado rplaca
para "substituir carro". Esta função raramente é vista, no entanto, como Common Lisp inclui um recurso especial, setf
, para facilitar a definição e o uso de funções destrutivas. Um estilo frequente no Common Lisp é escrever código funcionalmente (sem chamadas destrutivas) durante a prototipagem e, em seguida, adicionar chamadas destrutivas como uma otimização onde é seguro fazê-lo.
Formulários de autoavaliação e citações
Lisp avalia expressões que são inseridas pelo usuário. Símbolos e listas são avaliados para alguma outra expressão (geralmente, mais simples) – por exemplo, um símbolo é avaliado para o valor da variável que ele nomeia; (+ 2 3)
é avaliado como 5
. No entanto, a maioria dos outros formulários avalia para si mesmos: se inserir 5
em Lisp, ele retorna 5
.
Qualquer expressão também pode ser marcada para evitar que seja avaliada (como é necessário para símbolos e listas). Esta é a função da cotação
operador especial ou sua abreviação ' (uma aspa). Por exemplo, geralmente se inserir o símbolo
foo
, ele retorna o valor da variável correspondente (ou um erro, se tal variável não existir). Para se referir ao símbolo literal, digite (quote foo)
ou, normalmente, 'foo
.
Tanto Common Lisp quanto Scheme também suportam o operador backquote (denominado quasiquote em Scheme), inserido com o caractere `
(acento grave). Isso é quase o mesmo que as aspas simples, exceto que permite que as expressões sejam avaliadas e seus valores interpolados em uma lista entre aspas com a vírgula ,
coloque aspas e vírgula ,@
splicing operadores. Se a variável snue
tiver o valor (barra baz)
então `(foo ,snue)
avalia como (foo (barra baz))
, enquanto `(foo ,@snue )
é avaliado como (foo barra baz)
. A crase é usada com mais frequência na definição de expansões de macro.
Formulários de autoavaliação e formulários entre aspas são equivalentes de literais de Lisp. Pode ser possível modificar os valores de literais (mutáveis) no código do programa. Por exemplo, se uma função retorna um formulário entre aspas e o código que chama a função modifica o formulário, isso pode alterar o comportamento da função em invocações subsequentes.
(defuntos deve ser constante () '(um dois. três)(Deixa-me. (coisas (deve ser constante) (setf (terceiro coisas) Bizarro.) Mau!(deve ser constante) ; retorna (um dois bizarro)
Modificar um formulário citado como este geralmente é considerado um estilo ruim e é definido pelo ANSI Common Lisp como errôneo (resultando em comportamento "indefinido" em arquivos compilados, porque o compilador de arquivo pode unir constantes semelhantes, colocá-los na memória protegida contra gravação, etc.).
A formalização da citação de Lisp foi observada por Douglas Hofstadter (em Gödel, Escher, Bach) e outros como um exemplo da ideia filosófica de auto-referência.
Escopo e encerramento
A família Lisp se divide quanto ao uso de escopo dinâmico ou estático (também conhecido como léxico). Clojure, Common Lisp e Scheme fazem uso de escopo estático por padrão, enquanto newLISP, Picolisp e as linguagens incorporadas em Emacs e AutoCAD usam escopo dinâmico. Desde a versão 24.1, o Emacs usa escopo dinâmico e léxico.
Estrutura de lista do código do programa; exploração por macros e compiladores
Uma distinção fundamental entre Lisp e outras linguagens é que em Lisp, a representação textual de um programa é simplesmente uma descrição legível por humanos das mesmas estruturas de dados internas (listas vinculadas, símbolos, números, caracteres etc.) ser usado pelo sistema Lisp subjacente.
Lisp usa isso para implementar um sistema de macro muito poderoso. Como outras linguagens de macro, como a definida pelo pré-processador C (o pré-processador de macro para as linguagens de programação C, Objective-C e C++), uma macro retorna código que pode ser compilado. No entanto, ao contrário das macros do pré-processador C, as macros são funções Lisp e, portanto, podem explorar todo o poder do Lisp.
Além disso, como o código Lisp tem a mesma estrutura das listas, as macros podem ser construídas com qualquer uma das funções de processamento de lista na linguagem. Resumindo, qualquer coisa que o Lisp pode fazer em uma estrutura de dados, as macros Lisp podem fazer no código. Em contraste, na maioria das outras linguagens, a saída do analisador é puramente interna à implementação da linguagem e não pode ser manipulada pelo programador.
Esse recurso facilita o desenvolvimento de idiomas eficientes dentro de idiomas. Por exemplo, o Common Lisp Object System pode ser implementado de forma limpa como uma extensão de linguagem usando macros. Isso significa que, se um aplicativo precisar de um mecanismo de herança diferente, ele poderá usar um sistema de objetos diferente. Isso contrasta fortemente com a maioria das outras línguas; por exemplo, Java não suporta herança múltipla e não há uma maneira razoável de adicioná-la.
Em implementações simplistas de Lisp, essa estrutura de lista é interpretada diretamente para executar o programa; uma função é literalmente uma parte da estrutura da lista que é percorrida pelo interpretador ao executá-la. No entanto, os sistemas Lisp mais substanciais também incluem um compilador. O compilador traduz a estrutura da lista em código de máquina ou bytecode para execução. Esse código pode ser executado tão rápido quanto o código compilado em linguagens convencionais como C.
As macros se expandem antes da etapa de compilação e, portanto, oferecem algumas opções interessantes. Se um programa precisa de uma tabela pré-computada, uma macro pode criar a tabela em tempo de compilação, de modo que o compilador precisa apenas gerar a tabela e não precisa chamar o código para criar a tabela em tempo de execução. Algumas implementações de Lisp ainda possuem um mecanismo, eval-when
, que permite que o código esteja presente durante o tempo de compilação (quando uma macro precisaria dele), mas não presente no módulo emitido.
Avaliação e loop read-eval-print
Linguagens Lisp são freqüentemente usadas com uma linha de comando interativa, que pode ser combinada com um ambiente de desenvolvimento integrado (IDE). O usuário digita expressões na linha de comando ou direciona o IDE para transmiti-las ao sistema Lisp. Lisp lê as expressões inseridas, avalia e imprime o resultado. Por esta razão, a linha de comando Lisp é chamada de loop read–eval–print (REPL).
A operação básica do REPL é a seguinte. Esta é uma descrição simplista que omite muitos elementos de um Lisp real, como citações e macros.
A função ler
aceita S-expressões textuais como entrada e as analisa em uma estrutura de dados interna. Por exemplo, se você digitar o texto (+ 1 2)
no prompt, leia
traduz isso em uma lista encadeada com três elementos: o símbolo +
, o número 1 e o número 2. Acontece que esta lista também é uma parte válida do código Lisp; ou seja, pode ser avaliado. Isso ocorre porque o carro da lista nomeia uma função - a operação de adição.
Observe que um foo
será lido como um único símbolo. 123
será lido como o número 123. "123"
será lido como a string "123".
A função eval
avalia os dados, retornando zero ou mais outros dados Lisp como resultado. Avaliação não tem que significar interpretação; alguns sistemas Lisp compilam cada expressão em código de máquina nativo. É simples, entretanto, descrever avaliação como interpretação: Para avaliar uma lista cujo carro nomeia uma função, eval
primeiro avalia cada um dos argumentos fornecidos em seu cdr e, em seguida, aplica a função aos argumentos. Neste caso, a função é a adição e aplicá-la à lista de argumentos (1 2)
rendimentos a resposta 3
. Este é o resultado da avaliação.
O símbolo foo
avalia ao valor do símbolo foo. Dados como a string "123" avalia para a mesma string. A lista ( citação (1 2 3))
avalia para a lista (1 2 3).
É o trabalho da print
função para representar a saída para o usuário. Para um resultado simples como 3
isso é banal. Uma expressão avaliada para uma parte da estrutura da lista exigiria que print
percorrer a lista e imprimi-la como uma expressão S.
Para implementar um Lisp REPL, é necessário apenas implementar essas três funções e uma função de loop infinito. (Naturalmente, a implementação de eval
será complexo, pois também deve implementar todos os operadores especiais como if
ou lambda
.) Feito isso, um REPL básico é uma linha de código: (loop (imprimir (avaliar (ler))))
.
O Lisp REPL normalmente também fornece edição de entrada, um histórico de entrada, tratamento de erros e uma interface para o depurador.
Lisp geralmente é avaliado com entusiasmo. Em Common Lisp, os argumentos são avaliados na ordem do aplicativo ('mais à esquerda mais interno'), enquanto no Scheme a ordem dos argumentos é indefinida, deixando espaço para otimização por um compilador.
Estruturas de controle
Lisp originalmente tinha muito poucas estruturas de controle, mas muitas outras foram adicionadas durante a evolução da linguagem. (O operador condicional original de Lisp, cond
, é o precursor do posterior if-then-else
estruturas.)
Programadores no dialeto Scheme geralmente expressam loops usando recursão de cauda. A semelhança do esquema na ciência da computação acadêmica levou alguns alunos a acreditar que a recursão de cauda é a única, ou a mais comum, maneira de escrever iterações em Lisp, mas isso é incorreto. Todos os dialetos Lisp frequentemente vistos têm construções de iteração de estilo imperativo, do do
para o complexo Common Lisp loop
expressões. Além disso, a questão principal que torna isso um assunto objetivo e não subjetivo é que o Scheme faz requisitos específicos para o tratamento de chamadas de cauda e, portanto, a razão pela qual o uso de recursão de cauda é geralmente encorajado para Scheme é que a prática é expressamente suportada por a definição da linguagem. Por outro lado, o ANSI Common Lisp não requer a otimização comumente chamada de eliminação de chamada final. Assim, o fato de seguir o estilo recursivo como um substituto casual para o uso de construções de iteração mais tradicionais (como do
, dolist
ou loop
) é desencorajado em Common Lisp não é apenas uma questão de preferência estilística, mas potencialmente uma questão de eficiência (uma vez que uma aparente chamada de cauda em Common Lisp pode não compilar como um simples salto) e correção do programa (já que cauda recursão pode aumentar o uso de pilha em Common Lisp, arriscando estouro de pilha).
Algumas estruturas de controle Lisp são operadores especiais, equivalentes a outras linguagens' palavras-chave sintáticas. As expressões que usam esses operadores têm a mesma aparência de superfície que as chamadas de função, mas diferem porque os argumentos não são necessariamente avaliados — ou, no caso de uma expressão de iteração, podem ser avaliados mais de uma vez.
Em contraste com a maioria das outras linguagens de programação importantes, Lisp permite a implementação de estruturas de controle usando a linguagem. Várias estruturas de controle são implementadas como macros Lisp, e podem até ser macro-expandidas pelo programador que deseja saber como elas funcionam.
Tanto Common Lisp quanto Scheme possuem operadores para fluxo de controle não local. As diferenças nesses operadores são algumas das diferenças mais profundas entre os dois dialetos. O esquema suporta continuações reentrantes usando o call/cc
procedimento, que permite que um programa salve (e depois restaure) um determinado local em execução. Common Lisp não suporta continuações reentrantes, mas suporta várias maneiras de lidar com continuações de escape.
Muitas vezes, o mesmo algoritmo pode ser expresso em Lisp em um estilo imperativo ou funcional. Conforme observado acima, Scheme tende a favorecer o estilo funcional, usando recursão de cauda e continuações para expressar o fluxo de controle. No entanto, o estilo imperativo ainda é bem possível. O estilo preferido por muitos programadores Common Lisp pode parecer mais familiar para programadores acostumados a linguagens estruturadas como C, enquanto o preferido por Schemers se assemelha mais a linguagens puramente funcionais como Haskell.
Devido à herança inicial de Lisp no processamento de listas, ele possui uma ampla variedade de funções de ordem superior relacionadas à iteração sobre sequências. Em muitos casos em que um loop explícito seria necessário em outros idiomas (como um for
loop em C) em Lisp a mesma tarefa pode ser realizada com uma função de ordem superior. (O mesmo se aplica a muitas linguagens de programação funcionais.)
Um bom exemplo é uma função que em Scheme se chama map
e em Common Lisp é chamado mapcar
. Dada uma função e uma ou mais listas, mapcar
aplica a função sucessivamente às listas' elementos em ordem, coletando os resultados em uma nova lista:
(mapa # '+ '(1 2 3 4 5) '(10. 20. 30 40 50)
Isso aplica o +
para cada par correspondente de elementos da lista, gerando o resultado (11 22 33 44 55)
.
Exemplos
Aqui estão exemplos de código Common Lisp.
A mensagem básica "Hello, World!" programa:
(impressão "Olá, Mundo!")
A sintaxe do Lisp se presta naturalmente à recursão. Problemas matemáticos como a enumeração de conjuntos definidos recursivamente são simples de expressar nesta notação. Por exemplo, para avaliar o fatorial de um número:
(defuntos factorial (n) (se (zerop n) 1 (* n (factorial (1... n)))
Uma implementação alternativa ocupa menos espaço de pilha do que a versão anterior se o sistema Lisp subjacente otimizar a recursão de cauda:
(defuntos factorial (n > (acc 1) (se (zerop n) acc (factorial (1... n) (* acc n))
Compare os exemplos acima com uma versão iterativa que usa loop
:
(defuntos factorial (n) (loop para Eu... a partir de 1 para n para Fac... = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 1 então (* Fac... Eu...) finalmente (retorno Fac...)
A seguinte função inverte uma lista. (A função reverse integrada do Lisp faz a mesma coisa.)
(defuntos - reverso (lista) (Deixa-me. (valor de retorno) (lista de tarefas (e lista) (Empurre. e valor de retorno) valor de retorno)
Sistemas de objetos
Vários sistemas e modelos de objetos foram construídos em cima, ao lado ou dentro do Lisp, incluindo:
- O Common Lisp Object System, CLOS, é uma parte integrante do ANSI Common Lisp. CLOS desceu de Novos Sabores e CommonLOOPS. ANSI Common Lisp foi a primeira linguagem de programação orientada a objetos padronizada (1994, ANSI X3J13).
- ObjectLisp ou Object Lisp, usado por Lisp Machines Versões incorporadas e iniciais de Macintosh Common Lisp
- LOOPS (Lisp Object-Oriented Programming System) e o CommonLoops posterior
- Sabores, construídos no MIT, e seus novos sabores descendentes (desenvolvidos pela Symbolics).
- KR (short for Knowledge Representation), um sistema de objetos baseado em restrições desenvolvido para ajudar a escrever Garnet, uma biblioteca GUI para Common Lisp.
- O Knowledge Engineering Environment (KEE) usou um sistema de objetos chamado UNITS e o integrou com um motor de inferência e um sistema de manutenção da verdade (ATMS).
Sistemas operacionais
Vários sistemas operacionais, incluindo sistemas baseados em linguagem, são baseados em Lisp (usam recursos, convenções, métodos, estruturas de dados, etc.) ou são escritos em Lisp, incluindo:
Genera, renomeado Open Genera, pela Symbolics; Medley, escrito em Interlisp, originalmente uma família de sistemas operacionais gráficos executados nas estações de trabalho Star posteriores da Xerox; Mezanino; provisório; ChrysaLisp, por desenvolvedores da Tao Systems' TAOS.
Contenido relacionado
Dhrystone
KA9Q
DDR SDRAM