









Estude fácil! Tem muito documento disponível na Docsity
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Prepare-se para as provas
Estude fácil! Tem muito documento disponível na Docsity
Prepare-se para as provas com trabalhos de outros alunos como você, aqui na Docsity
Encontra documentos específicos para os exames da tua universidade
Prepare-se com as videoaulas e exercícios resolvidos criados a partir da grade da sua Universidade
Responda perguntas de provas passadas e avalie sua preparação.
Ganhe pontos para baixar
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
artigo final do trabalho da disciplina de Linguagens de Programação do 4º período de Engenharia de Computação do Ceunes-Ufes. Eu estudei as linguagens Scheme e Common Lisp, que são os dialetos mais comuns do lisp na atualidade. Este artigo faz um apanhado geral de ambas linguagens, falando sobre a sintaxe, histórico, métodos de implementação, amarrações, sistema de tipo, exceções, etc. disciplina ministrada pelo prof. Ayrton Monteiro Cristo.
Tipologia: Manuais, Projetos, Pesquisas
1 / 15
Esta página não é visível na pré-visualização
Não perca as partes importantes!










UFES - Universidade Federal do Esp´ırito Santo Centro Universit´ario Norte do Esp´ırito Santo Departamento de Engenharia e Ciˆencia Exatas Engenharia de Computa¸c˜ao S. Mateus - ES - Brasil
Resumo LISP foi a primeira linguagem de programa¸c˜ao a implementar concei- tos de programa¸c˜ao funcional. Scheme e Common Lisp s˜ao os dialetos do Lisp com uso mais generalizado atualmente. Este trabalho pretende fazer uma descri¸c˜ao destas duas linguagens enfatizando os conceitos, t´ecnicas e propriedades gerais de Linguagens de Programa¸c˜ao implementadas nestas linguagens.
Palavras-chave: Linguagens de Programa¸c˜ao, LISP, Scheme, Com- mon Lisp.
O advento da linguagem de programa¸c˜ao LISP, idealizada por John McCarthy entre 1956 e 1958 com o objetivo de ser usada em Inteligˆencia Artificial (IA) e em processamento alg´ebrico simb´olico, marcou o in´ıcio do chamado para- digma funcional de programa¸c˜ao. Os fundamentos matem´aticos deste para- digma encontram-se no c´alculo-lambda, criado por Alonzo Church, na d´ecada de 30. A estrutura do LISP permite que sejam feitas modifica¸c˜oes e extens˜oes a linguagem, ou at´e mesmo a cria¸c˜ao de novos dialetos da linguagem, com uma certa facilidade. Devido a esta caracter´ıstica particular, diversos dialetos do LISP apareceram em institui¸c˜oes de ensino, empresas privadas, grupos de pes- quisas ou at´e mesmo como projetos pessoais, sendo que, inicialmente, pouca ou nenhuma padroniza¸c˜ao foi adotado para o LISP. Muitos destes dialetos se tor- naram obsoletos ou s˜ao encontrados somente em alguns sistemas operacionais ou softwares espec´ıficos. Scheme e Common Lisp s˜ao os dois maiores dialetos do LISP em uso atualmente. Neste artigo iremos,a luz do conceitos de lin- guagens de programa¸c˜ao, estudar as principais caracter´ısticas das linguagens de programa¸c˜ao Scheme e Common Lisp.
N˜ao se pretende fazer uma descri¸c˜ao hist´orica detalhada do LISP, visto que existe na literatura artigos que j´a a fizeram. McCarthy [2] divide a hist´oria do LISP em trˆes per´ıodos, o primeiro ´e denominado “pr´e-hist´oria” do LISP, entre o ver˜ao de 1956 e 1958, durante o qual as principais ideias da linguagem foram concebidas, entre 1958 e 1962, durante o qual a linguagem foi implementada e utilizada na resolu¸c˜ao de problemas de inteligˆencia artificial e ap´os 1962, que v´arias ideias foram incorparadas `a linguagem e diversas implementa¸c˜oes foram feitas, em geral cada uma seguindo caminhos distintos. A principal motiva¸c˜ao de McCarthy na concep¸c˜ao da linguagem era de facilitar experimentos com um sistema proposto ao grupo de Inteligˆencia Artificial do MIT, chamado Advice Taker. O sistema deveria receber instru¸c˜oes declarativas e imperativas e exibir senso comum aos cumprir as instru¸c˜oes. Fazia-se necess´ario ent˜ao um sistema de programa¸c˜ao capaz de manipular express˜oes simb´olicas que representassem as senten¸cas declarativas e imperativas, de modo que o Advice Taker pudesse fazer dedu¸c˜oes. A estrutura de dados para representar as express˜oes e os dados esco- lhida foi as chamadas S-Expressions (express˜oes simb´olicas). Uma S-expression ´e um express˜ao que contem os seguintes s´ımbolos ’(’ e ’)’ delimitando o come¸co e o fim da express˜ao, e ´atomos, que s˜ao sequˆencias de letras que tem como ´unica propriedade serem iguais se forem escritas da mesma maneira. Os operadores de uma express˜ao-S s˜ao pr´e-fixados. Steele e Gabriel [1] partem do artigo de MacCarthy e fazem uma digress˜ao hist´orica entre as principais implementa¸c˜oes e dialetos do LISP que apareceram entre 1960 e 1993, culminando nos esfor¸cos de padroniza¸c˜ao do LISP e o aparecimento do Common Lisp. E feito um estudo´ da evolu¸c˜ao de algumas caracter´ısticas espec´ıficas da linguagem ao longo dos anos.
Scheme foi projetada em 1975,por Guy Steele e Gerald Sussman, enquanto trabalhavam do Laborat´orio de Inteligˆencia Artificial do MIT. Scheme foi pro- jetado para ter uma sintaxe e semˆantica simples e trazer conceitos modernos de linguagem de programa¸c˜ao para a comunidade Lisp (mais precisamente estru- tura de blocos aninhados ALGOL-like, procedimentos, fun¸c˜oes e continua¸c˜oes como objetos de primeira classe, escopo est´atico, etc).
O Common Lisp ´e fruto de um esfor¸co de diversas equipes de projetistas de LP, cientistas e entusisatas da comunidade LISP, na produ¸c˜ao de um dialeto LISP que padronizasse as principais variantes do LISP. E uma linguagem grande, que´ surgiu como tentativa de juntar em uma especifica¸c˜ao contribui¸c˜oes de prati- camente todos os maiores dialetos do LISP (sucessor do MacLisp, fortemente influenciado pelo ZetaLisp e em parte pelo Scheme e InterLisp).
2 Propriedades e Caracter´ısticas Gerais de Scheme
e Common Lisp
Nesta se¸c˜ao iremos tratar das caracter´ısticas e propriedades do Scheme e Com- mon Lisp segundo crit´erios usuais em estudo de Linguagens de Programa¸c˜ao.
O principal paradigma de programa¸c˜ao do LISP, Scheme e Common Lisp ´e o funcional, mas estas LPs n˜ao s˜ao consideradas puramente funcionais, visto que existem constru¸c˜oes na linguagem que s˜ao caracter´ısticas do paradigma imperativo por envolverem mudan¸ca de estado na mem´oria (em Scheme temos, por exemplo, o (set! a b) que muda o estado da vari´avel a). O Common Lisp tamb´em suporta programa¸c˜ao orientada a objetos. O subconjunto da linguagem que ´e puramente funcional ´e usualmente denominado “Lisp Puro”.
O m´etodo mais de comum de implementa¸c˜ao das linguagens em estudo ´e a interpreta¸c˜ao. Devido a sintaxe simples e ao uso da mesma representa¸c˜ao ex- terna para dados e c´odigo de programas (espress˜oes-S), ´e relativamente f´acil implementar um interpretador. Existem tamb´em compiladores para Scheme e CL (Common Lisp). O pr´oprio Steele projetou um compilador para Scheme chamado Rabbit. Existem diversos compiladores para o CL. O CLISP ´e uma implementa¸c˜ao do Common Lisp, que inclue um interpretador e um compi- lador byte-code, ´e um software gratuito e faz parte do Projeto GNU e est´a dispon´ıvel sob a licen¸ca GPL (GNU General Public License). Um outro compi- lador gratuito de CL ´e o GNU Common Lisp (GCL) que compila para um codigo intermedi´ario em C, e depois chama o compilador de C que gera o execut´avel.
3 Amarra¸c˜oes
Uma amarra¸c˜ao ´e uma associa¸c˜ao entre entidades de programa¸c˜ao. O tempo de amarra¸c˜ao ´e o momento que esta vincula¸c˜ao se desenvolve. Ambos con- ceitos s˜ao importantes na semˆantica das linguagens de programa¸c˜ao. Neste t´opicos iremos tratar de como s˜ao feitas as amarra¸c˜oes em Scheme e CL. Antes de come¸carmos a efetivamente explorar o assunto devemos saber como referir a uma entidade de programa¸c˜ao. Usualmente na defini¸c˜ao da linguagem s˜ao escolhidas maneiras de se referir a uma entidade de programa¸c˜ao atrav´es dos identificadores, que geralmente s˜ao cadeias de caracteres que servem de “nome” para uma entidade. N˜ao ´e qualquer cadeia de caracter que serve de identifica- dor. Do universo de todas sequˆencias de caracteres ´e definido um subconjunto, fazendo uso de algumas regras, que poder˜ao ser utilizadas como identificadores v´alidos. Em Scheme este conjunto de identificadores v´alidos pode variar um pouco em implementa¸c˜oes diferentes, no entanto todas implementa¸c˜oes devem seguir algumas regras gerais na forma¸c˜ao de identificadores. Como regra geral um identificador v´alido n˜ao pode come¸car com um n´umero, portanto qualquer sequˆencia de caracteres que tenha como primeiro caracter uma letra ou um “ca- racter especial” ( & $ % { } ˆ ˜ ! * / : < = > ?) ´e um identificador v´alido. A sintaxe formal dos indentificadores em Scheme escrita na Forma Extendida
de Backus-Naur (EBNF) pode ser encontrada por exemplo na se¸c˜ao 7.1.1 do Revised^5 Report (R^5 RS). Scheme e CL n˜ao s˜ao case sensitive.
O ambiente de amarra¸c˜ao em um ponto ´e o conjunto de todas amarra¸c˜oes vis´ıveis neste ponto. ´E atrav´es do ambiente de amarra¸c˜ao que ´e determinado o significado de cada identificador ao longo do programa. Nem toda amarra¸c˜ao ´e vis´ıvel em todo programa, uma amarra¸c˜ao est´a sujeita a um escopo de visibili- dade, que ´e uma regi˜ao do programa onde a amarra¸c˜ao ´e vis´ıvel. Este escopo pode ser est´atico ou dinˆamico. No escopo est´atico o ambiente de amarra¸c˜ao ´e determinado antes da execu¸c˜ao do programa, pela organiza¸c˜ao do texto, e por- tanto estaticamente. O projeto da linguagem Scheme rompeu com a tradi¸c˜ao dos dialetos anteriores do LISP e adotou escopo est´atico e, seguindo o projeto do Algol, uma estrutura de blocos aninhadas. Essa mudan¸ca de atitude em rela¸c˜ao ao escopo de vari´aveis foi muito influente na comunidade LISP, de modo que o Common Lisp adotou tamb´em por padr˜ao o escopo est´atico, embora exista a possibilidade de uma vari´avel ter escopo dinˆamico se ela for explicitamente de- clarada como uma vari´avel “especial”. Uma vari´avel pode ser declarada como “especial” usando o procedimento defvar. Vari´aveis “especiais” s˜ao normal- mente utilizadas como vari´aveis globais.
Embora seja um conceito ligeiramente distinto do de ambiente de amarra¸c˜ao, citaremos o conceito de namespace existente em CL, que ´e um conjunto de amarra¸c˜oes restritas a algum tipo. Um objeto do tipo package determina um namespace, ele faz o mapeamento de um nome de s´ımbolo para um s´ımbolo. Em CL podemos ter identificadores no mesmo programa que pertencem a na- mespaces diferentes, por exemplo, fun¸c˜oes e vari´aveis pertencem a namespaces diferentes. Tomemos o seguinte exemplo, (defun x (x) (+ x 1)). Neste caso o identificador x depois de defun designa o nome da fun¸c˜ao, e portanto pertence ao namespace das fun¸c˜oes, o x usado como vari´avel ligada pertence ao names- pace das vari´aveis e, portanto n˜ao existe conflito algum referente `a denota¸c˜ao do identificador em cada ponto do programa. Se o argumento de uma fun¸c˜ao ´e uma outra fun¸c˜ao, ela deve ser explicitamente declarada como tal, usando o operador especial “function” ou a sua abrevia¸c˜ao #’. J´a em Scheme n˜ao existe distin¸c˜ao entre namespace de fun¸c˜oes e de vari´aveis, o que proporciano uma certa flexi- bilidade ao programador na hora de criar fun¸c˜oes mais gen´ericas. Existe uma controv´ersia na comunidade LISP se um namespace de fun¸c˜oes separados do de vari´aveis ´e, de fato, uma desvantagem, essa controv´ersia ´e conhecida como Debate Lisp-1 vs. Lisp-2.
N˜ao existe uma maneira de declarar ou definir constantes explicitamente em Scheme e CL. E poss´´ ıvel criar uma amarra¸c˜ao entre um identificador e um valor. Este valor ser´a constante, mas a qualquer momento ´e poss´ıvel criar uma nova amarra¸c˜ao com este mesmo identificador a um novo valor. Mesmo amarra¸c˜oes pr´e-definidas podem ser refeitas. Em Scheme fun¸c˜oes e vari´aveis pr´e-definidas podem ser redefinidas (´e perfeitamente legal a defini¸c˜ao (define sin 7)). Em CL somente vari´aveis pr´e-definidas podem ser redefinidas, um package pode
(define nomefunc (lambda (argumentos) corpo)) (define (nomefunc argumentos) corpo)
Em CL a defini¸c˜ao de fun¸c˜oes ´e feita usando o macro defun. Segue a sintaxe de defini¸c˜oes de fun¸c˜oes em CL: (defun nomefunc (argumentos) corpo)
A defini¸c˜ao de fun¸c˜oes em LPs cujo principal paradigma ´e o funcional, em geral se d´a atrav´es de defini¸c˜oes recursivas. Scheme e CL n˜ao fogem a regra, de modo que, n˜ao obstante em ambas linguagens haver fun¸c˜oes especiais que permitem fazer repeti¸c˜oes no estilo imperativo, usando itera¸c˜oes com loops, o uso de recurs˜ao nestes casos e generalizado em ambas linguagens. E poss´´ ıvel fazer defini¸c˜oes sequˆenciais utilizando o let, lambda e begin em Scheme. (define (somavarios g) (let (x 2) (y (+ x 1)) (- (* y x) g)))
(define somavarios (lambda (g) (define x 2) (define y (+ x 1)) (- (* y x) g)))
4 Tipos de Dados
Discutiremos inicialmente o sistema de tipos de dados do Scheme, e em se- guida faremos uma breve discuss˜ao dos tipos de dados do CL, visto este ser extenso e complexo. Scheme ´e uma linguagem fracamente tipada e a verfica¸c˜ao de tipos ´e feita dinamicamente em tempo de execu¸c˜ao. Temos fun¸c˜oes que se aplicam a qualquer tipo de lista, funcionam para praticamente todos os tipos da hierarquia de tipos num´ericos e que aceitam praticamente qualquer tipo de parˆametro (eval). O R^5 RS define uma disjun¸c˜ao dos seguintes tipos de dados em Scheme: number symbol(atoms) char vector pair (lists) string port procedure (function) Nenhum valor ou objeto Scheme pode pertencer a mais de dos tipos supracita- dos.
A comunidade Lisp tradicionalmente nunca se dedicou muito `a computa¸c˜ao num´erica. No projeto do Common Lisp foram adotadas estrat´egias cuidado- samente elaboradas pensando na otimiza¸c˜ao de c´odigo e organiza¸c˜ao da com- puta¸c˜ao num´erica. Scheme adota estas recomenda¸c˜oes e implementa um sis- tema simplificado e generalizado de tipos num´ericos do CL consistente com os prop´ositos do projeto da linguagem. O sistema de tipos num´ericos formam uma torre de subtipos, segundo uma classifica¸c˜ao matem´atica relativa a classe de n´umeros que estes subtipos representam: number complex real rational integer
Os n´umeros em Scheme s˜ao tratados como dados abstratos e toda opera¸c˜ao sobre os n´umeros tenta se afastar o m´aximo poss´ıvel da sua representa¸c˜ao na m´aquina. E feita uma distin¸´ c˜ao entre os n´umeros Scheme e sua representa¸c˜ao na m´aquina, podendo haver at´e duas representa¸c˜oes de um n´umero, por exemplo usando ponto flutuante (flonum) e ponto fixo (fixnum).
Uma propriedade importante dos n´umeros Scheme, ´e a distin¸c˜ao entre n´umeros exatos e inexatos. Um n´umero ´e exato se pode ser escrito como uma constante exata, ou derivado de um conjunto de opera¸c˜oes exatas sobre n´umeros exatos, caso contr´ario ´e inexato. Qualquer n´umero da torre de subtipos num´ericos pode ser exato ou inexato, a exatid˜ao n˜ao ´e propriedade do tipo do n´umero, mas sim de como o n´umero foi definido (ou das opera¸c˜oes que deram como resultado o n´umero).
No R^5 RS n˜ao ´e requerido que uma implementa¸c˜ao de Scheme suporte toda a torre de subtipos num´ericos, no entanto ela deve implementar um subcon- junto coerente da torre. Quanto `a cardinalidade dos tipos n˜ao ´e feita nenhuma exigˆencia, exceto que uma implementa¸c˜ao deve dar suporte a n´umeros intei- ros exatos de cardinalidade suficiente para serem usados como ´ındices de listas, vetores e strings. E recomendado que as implementa¸´ c˜oes suportem n´umeros exa- tos de tamanho praticamente ilimitado e que, caso suportem n´umeros de ponto flutuante, sigam as recomenda¸c˜oes das padr˜ao de 32-bit e 64-bit da IEEE.
Um Pair(par) ´e uma estrutura de registro com dois campos chamadas (por motivos hist´oricos) de car (Address Register) e cdr (Decrement Register). Para criar um valor do tipo par, usamos a fun¸c˜ao (cons a b) e para acessarmos os campos car e cdr, usamos fun¸c˜oes homˆonimas aos campos.
Este tipo de dado ´e usado para definir listas recursivamente. Um lista ´e empty (que ´e um tipo especial) ou ´e uma par cujo campo cdr contem uma lista. Os objetos nos campos car s˜ao os elementos da lista. Lista ´e a estrutura de dados usada para representar tanto dados como programas.
5 Vari´aveis e Constantes
Na se¸c˜ao de amarra¸c˜oes vimos como criar um vari´avel em Scheme e Common Lisp, usando os macros define, let e setf. Nesta se¸c˜ao iremos concentrar no entendimento do conceito de vari´aveis e constantes tendo em vista um modelo de armazenamento de vari´aveis e constantes.
Conceitualmente podemos pensar nas vari´aveis como ponteiros para valores na mem´oria. Estes valores s˜ao imut´aveis, o valor do n´umero 1 ´e uma entidade na mem´oria que ´e ´unica e n˜ao pode ser alterada, da mesma forma o valor do symbol ’2. Se fizermos (define x 1)estamos criando a vari´avel x e fazendo ela apontar para o valor do n´umero 1. Se em seguida for avaliado o comando (set! x ’a), o valor 1 n˜ao foi alterado, ele s´o deixou de ser referenciado e a vari´avel x passou a referenciar um outro valor. Um procedimento que tem argumentos num´ericos e retorna um n´umero na verdade est´a recebendo um ponteiro para um n´umero e retornando um ponteiro para um n´umero. Para o programador e o usu´ario final n˜ao importa se est˜ao sendo utilizados ponteiros ou valores. O fato ´e que ao passarmos ponteiros para as fun¸c˜oes, por exemplo, as opera¸c˜oes matem´aticas se tornam mais coerentes, visto que matematicamente falando um n´umero ´e uma entidade ´unica,e portanto ao usarmos este modelo de armazenamento nos aproximamos do ponto de vista matem´atico.
A maior parte das vari´aveis em Scheme e CL, principalmente as criadas atrav´es do define, defun, let e setf, s˜ao apontadores para objetos que s˜ao alo- cados no monte. Os objetos contˆem um campo de prop´osito geral chamado de value cell (c´elula de valor), este campo pode conter qualquer valor: um valor imediato (um n´umero, symbol) ou um apontador para uma outra localiza¸c˜ao da mem´oria (campo cdr de uma lista n˜ao vazia). Os pares (pair ) s˜ao exemplos de objetos que contem dois campos, cada podendo armazenar qualquer valor.
Este modelo de armazenamento facilita a aloca¸c˜ao de novos objetos na mem´oria, no entanto ´e necess´ario ter uma gerˆencia dos objetos na mem´oria que efetiva- mente est˜ao sendo usados pelo programa para que o sistema n˜ao fique sem mem´oria. O Garbage Collector (Coletor de Lixo) ´e o componente do sistema respons´avel por fazer o trabalho de reclamar a mem´oria de objetos que n˜ao s˜ao mais utilizados pelo programa.
6 Express˜oes e Comandos
Como LPs cujo principal foco ´e a programa¸c˜ao funcional, Scheme e CL s˜ao orientadas a express˜oes - grande parte das constru¸c˜oes da linguagem retornam um valor. Embora tenha alguns comandos, estes s˜ao poucos. As express˜oes e comandos podem ser divididas em primitivos e derivados.
S˜ao classificadas como express˜oes e comandos primitivos as seguintes ex- press˜oes:
Sintaxe: (if (teste) consequente) (if (teste) consequente alternativo) Teste ´e uma express˜ao que deve retornar um valor l´ogico. Caso verdadeiro a express˜ao condicional retorna o valor da express˜ao consequente, caso contr´ario, retorna o resultado da express˜ao alternativo. (if (> x 0) x (- 0 x)) ;;valor absoluto
puta¸c˜ao” em um ponto do programa. Atrav´es do uso do procedimento call-with-current-continuation ´e poss´ıvel “empacotar” um est´agio de uma computa¸c˜ao dentro de uma fun¸c˜ao e retornar a continua¸c˜ao para uma ou- tra fun¸c˜ao que eventualmente poder´a invocar a continua¸c˜ao da primeira fun¸c˜ao. Em Scheme as continua¸c˜oes tˆem status de objetos de primeira classe, podendo ser passados como parˆametros de fun¸c˜oes, atribuidos a vari´aveis e retornados por fun¸c˜oes, contudo s˜ao elementos perigosos pois s˜ao considerados os “gotos” do Scheme. Common Lisp provˆe express˜oes categ´oricas tais como o typeof, typep, type,etc
7 Modulariza¸c˜ao e Polimorfismo
Scheme e CL provˆem mecanismos diferentes de modulariza¸c˜ao compat´ıveis com a filosofia do projeto de cada um. Em Scheme o mecanismo b´asico de modulariza¸c˜ao ´e a abstra¸c˜ao de processos atrav´es de fun¸c˜oes. Scheme n˜ao provˆe mecanismos espec´ıficos para a abstra¸c˜ao de dados, mas essa pode ser emulada atrav´es do uso de listas, vetores e fun¸c˜oes.
Nos subprogramas Scheme a dire¸c˜ao de passagem de parˆametro ´e unidirecional de entrada, normalmente ´e utilizada o modo normal (eager ) de avalia¸c˜ao, no qual o parˆametro real ´e avaliado no momento da chamada da fun¸c˜ao. E poss´´ ıvel simular “lazy evaluation” atrav´es de uma sintaxe especial que explicitamente suspende a computa¸c˜ao (os procedimentos delay e force). Todos os parˆametros s˜ao passados por valor.
O Common Lisp possui alguns mecanismos extras de implementar Modula- riza¸c˜ao. Atrav´es do seu sistema de tipo, usando os procedimentos de especi- fica¸c˜ao de tipos novos, ou de dados estruturados (defstruct) ´e implementado abstra¸c˜ao de dados. Com o defstruct ´e definido uma estrutura de dados seme- lhantes ao struct do C: um registo com alguns campos definidos.
Um suporte maior `a modulariza¸c˜ao em CL pode ser alcan¸cado atrav´es dos pacotes (packages). O package ´e uma estrutura de dados que faz um mapea- mente entre nome (strings) e symbols, ele define um namespace. Em um dado momento um package ´e o package atual do sistema e ´e utilizado pelo lisp re- ader na tradu¸c˜ao de strings para symbols. O package atual do sistema ´e, por defini¸c˜ao, definido pelo valor da vari´avel global package.
O mapeamento de strings para symbols dispon´ıvel em um pacote ´e dividido em duas classes: externos e internos. Os s´ımbolos externos fazem parte da interface p´ublica do pacote, e devem ser declarados especialmente como tal, atrav´es da palavra chave export. O sistema de pacotes ´e multi-camada, podendo ter pacotes que herdam namespace de outros pacotes. Um novo pacote ´e definido atrav´es do procedimento defpackage, atrav´es do qual pode ser definido o tamanho do pacote (n´umero de s´ımbolos), apelidos, s´ımbolos internos e externos, etc. O procedimento use-package permite o uso de um pacote espec´ıfico.
O CL possui um sistema orientada a objetos chamado Common Lisp Object System (CLOS). O CLOS ´e baseado em fun¸c˜oes gen´ericas, heran¸ca m´ultipla, combina¸c˜ao declarativa de m´etodos e um protocolo de meta-objetos. Os objetos fundamentos do CLOS s˜ao classes,instˆancias,fun¸c˜oes gen´ericas e m´etodos. Um objetod do tipo class determina a estrutura e comportamento de outros objetos, que s˜ao chamadados de instˆancias desta classe. O conjunto de opera¸c˜oes que podem ser efetuados sobre um objeto pode ser determinado atrav´es da classe deste objeto.
Um fun¸c˜ao gen´erica ´e uma fun¸c˜ao cujo comportamento depende da classe dos argumentos da fun¸c˜ao. Este ´e um exemplo claro de polimorfismo param´etrico universal de fun¸c˜oes, visto que podemos definir fun¸c˜oes gen´ericas que opera- rariam sobre objetos de diversas classes e comportariam para cada classe de uma maneira diferente. Fun¸c˜oes Gen´ericas s˜ao conhecidas tamb´em por multi- m´etodos. Um objeto generic funtion, entre outras informa¸c˜oes, contem um con- junto de m´etodos e um tipo de combina¸c˜ao de m´etodos. Um m´etodo define com- portamentos e opera¸c˜oes espec´ıficas a uma classe, diz-se que um m´etodo especi- aliza uma fun¸c˜ao gen´erica. Um objeto method contem uma fun¸c˜ao do m´etodo, uma sequˆencia de especializadores de parˆametros que determinam quando que o m´etodo ´e aplic´avel, e uma sequˆencia de qualificadores para que o combinador de m´etodos possa distinguir entre m´etodos diferentes que operam em classes di- ferentes. O combinador de m´etodos controla a sele¸c˜ao dos m´etodos, a order que s˜ao executados e os valores retornados pelas fun¸c˜oes gen´ericas. O CLOS provˆe um tipo de combina¸c˜ao de m´etodos padr˜ao ´e provˆe procedimentos de declarar nos tipos de combina¸c˜oes de m´etodos.
Cada classe do CLOS tem uma lista de precedˆencia de classes, que ´e uma ordena¸c˜ao da classe e o conjunto de suas superclasses. O ordem da lista ´e da mais espec´ıfica para a menos espec´ıfica. Esta lista ´e usada pelo Combinador de M´etodos para ordenar os m´etodos na ordem do mais espec´ıfico para o me- nos espec´ıfico. Algumas classes podem sobescrever ou cubrir caracter´ısticas e m´etodos de suas superclasses. A defini¸c˜ao de classes ´e feita usando o procedi- mento defclass. O CLOS ´e dinˆamico, de modo que as classes e os m´etodos do CLOS podem ser redefinidos em tempo de execu¸c˜ao, mesmo se j´a exista uma objetos instanciados da classe em quest˜ao.
8 Exce¸c˜oes
Em Scheme n˜ao existia nenhum tipo de procedimentos ou meios da pr´opria linguagem para manipula¸c˜ao de exce¸c˜oes, embora existisse meios de sinaliz´a- las, mas na ´ultima vers˜ao do Revised Report(R^6 RS), seguindo o projeto do Common Lisp, foi acrescentado `a linguagem, atrav´es da biblioteca padr˜ao, o tipo condition, um conjunto de fun¸c˜oes que permite a sinaliza¸c˜ao e manipula¸c˜ao de excep¸c˜oes, e uma s´erie de tipos de condi¸c˜oes padr˜ao. O tratamento de excep¸c˜oes pode ser feito com o uso dos procedimentos guard e raise. O R^6 RS ainda ´e novo, foi ratificado no final de 2007, e portanto n˜ao existem ainda muitas implementa¸c˜oes dele.