Vous êtes sur la page 1sur 13

Modelos de Linguagens de Programacao An lise da linguagem Common Lisp a

Vtor Buj s Ubatuba De Araujo1 , Caio Licks Pires Miranda1 e


1

Instituto de Inform tica Universidade Federal do Rio Grande do Sul (UFRGS) a Caixa Postal 15.064 91.501-970 Porto Alegre RS Brazil

1. Introducao
Neste trabalho desenvolvemos um interpretador para uma linguagem de programacao simples, chamada MLP. MLP e uma linguagem com sintaxe estilo ALGOL, com su porte a funcoes de primeira classe. O interpretador, escrito em Common Lisp, e capaz de mostrar o estado da pilha de registros de ativacao durante a execucao do programa interpretado, incluindo os valores das vari veis locais, e de utilizar tanto escopo est tico a a quanto din mico no acesso de vari veis n o-locais. Foi usada a biblioteca gr ca Ltk para a a a a o desenvolvimento da interface.

2. Common Lisp
Lisp e uma famlia de linguagens de programacao que derivam em ultima inst ncia da a linguagem criada por John McCarthy em 1958 [McCarthy 1960]. H diversas linguagens a nessa famlia, das quais as principais ainda em uso s o o Scheme e o Common Lisp. a Scheme[Sussman e Steele, 1975] e uma linguagem que objetiva ser pequena e altamente ortogonal; o documento que dene a linguagem possui cerca de 50 p ginas. O Common a Lisp[Steele 1990], pelo contr rio, surgiu em uma tentativa de unicar os dialetos de Lisp a mais importantes da epoca (d cada de 1980), e representa uma uni o das funcionalidades e a desses dialetos. Por conseguinte, a linguagem e bastante extensa, possuindo suporte tanto a programacao funcional e imperativa quanto um sistema de orientacao a objetos notavel mente complexo, o CLOS. A seguir, s o apresentadas as principais caractersticas do Common Lisp. a 2.1. S-expressions e macros Uma importante caracterstica das linguagens da famlia Lisp e o fato de que o c digo dos o programas e representado por estruturas de dados da pr pria linguagem, coletivamente o denominadas S-expressions. Por exemplo, a lista (+ 2 3) representa a aplicacao da funcao + aos argumentos 2 e 3. + e um smbolo (uma estrutura de dados especca do Lisp), 2 e 3 s o n meros, e os par nteses s o usados para delimitar listas. Quando uma a u e a lista representando c digo e avaliada ou compilada, o primeiro elemento da lista e tratado o como uma funcao a ser aplicada aos argumentos restantes. Essa caracterstica d ao Lisp sua sintaxe peculiar, e tamb m e fonte de uma das a e propriedades mais interessantes da linguagem: pode-se estend -la arbitrariamente com e novas construcoes sint ticas, atrav s de transformacoes de c digo realizadas sobre as lis a e o tas que o comp em. Isso se d em geral atrav s da denicao de macros, funcoes que o a e mapeiam arvores de c digo em novas arvores de c digo. Por exemplo, se quis ssemos o o e criar uma nova construcao similar ao while de linguagens imperativas, poderamos deni-la como uma transformacao de c digo em termos de if e tagbody/go (o equiv o alente do goto do Common Lisp):

(defmacro while (test &rest body) (tagbody start (if ,test (progn ,@body (go start))))) No trabalho, foi utilizada uma macro para introduzir uma construcao para criacao de lazy lists, como ser visto mais adiante. a 2.2. Funcoes de primeira classe Em Lisp, funcoes s o elementos de primeira classe, isto e, podem ser usadas como qual a quer outro valor da linguagem, podendo ser passadas como par metro ou retornadas como a funcoes. O Common Lisp usa escopo est tico por padr o; se uma funcao g e retornada por a a uma outra funcao f, g ser capaz de acessar as vari veis denidas de f que s o visveis a a a em seu escopo, mesmo depois de f ter retornado. O uso de tais funcoes associadas a ambientes, denominadas closures, e bastante comum em Common Lisp. Ao contr rio do Scheme, Common Lisp e um Lisp2 [Pitman e Gabriel, 1988]. Exa istem dois namespaces onde valores de vari veis podem ser procurados: um usado para a procurar o valor do primeiro elemento de uma lista a ser avaliada, e que cont m exclusivae mente funcoes, macros e operadores especiais, e um usado para as vari veis comuns, sem a restricao sobre os tipos dos valores que cont m (que podem inclusive ser funcoes). Isso e signica que e possvel ter uma funcao e uma vari vel com o mesmo nome. A principal a vantagem pr tica disso e que o potencial de causar conitos de nomes na expans o de a a macros e bastante reduzido. Por exemplo, considere o seguinte c digo: o (defun foo (list) (hack list)) Em um Lisp1 , isto e, um Lisp em que o mesmo ambiente e usado para a avaliacao da funcao e das vari vies comuns, esse trecho faz com que no escopo da funcao foo a a vari vel list substitua a funcao list da biblioteca padr o, que cria uma lista com os a a elementos passados a ela como argumentos. Isso aparentemente n o e um problema, pois a essa funcao n o e usada no corpo de foo. Por m, hack poderia ser uma macro denida a e como: (defmacro hack (arg) (list ,arg ,arg)) Com isso, a denicao de foo, ap s a expans o da macro, e: o a (defmacro foo (list) (list list list)) O que causaria um conito de nomes n o evidente no corpo original de foo. Um a Lisp2 elimina uma parte signicativa dos possveis conitos de nomes em expans o de a macros; outros conitos permanecem, mas s o mais f ceis de tratar do que substituicao a a de funcoes da biblioteca padr o. Outros Lisps, tais como o Scheme, resolvem o problema a atrav s do uso de macros higi nicas, que impedem a captura de nomes, mas s o ou menos e e a

exveis ou mais complicadas de usar do que as macros baseadas em S-expressions puras dos Lisps tradicionais. E possvel usar um valor do namespace de funcoes como um valor comum, atrav s da sintaxe #nome. Tamb m e possvel invocar um valor comum como e e funcao usando a forma (funcall valor argumentos...), ou (apply valor lista-de-argumentos). Tamb m e possvel criar funcoes an nimas, usando a sine o taxe (lambda (arg1 arg2 ...) corpo). 2.3. Orientacao a objetos O Common Lisp possui um sistema de orientacao a objetos bastante exvel, o CLOS (Common Lisp Object System). Em comum com outras linguagens, e um sistema com heranca m ltipla e dispatch din mico. O CLOS e adaptado ao estilo funcional: ao inv s u a e da sintaxe objeto.mtodo(argumentos) usada por outras linguagens, o CLOS e utiliza a sintaxe (mtodo objeto argumentos), da mesma forma que funcoes e comuns. M todos n o pertencem a classes; em vez disso, todos os m todos de mesmo e a e nome s o agrupados sob uma mesma generic function. Quando uma generic function e a chamada, os tipos dos argumentos passados determinam o m todo a ser chamado. Generic e functions s o elementos de primeira classe, que podem ser usadas em qualquer lugar em a que funcoes comuns s o aceitas, inclusive como par metro ou valor de retorno de outras a a funcoes. O CLOS suporta multim todos: os tipos de todos os argumentos s o usados para e a determinar o m todo a ser chamado. A possibilidade de especializar um m todo em e e m ltiplos argumentos supre um dos casos de uso mais comuns de pattern matching, e u foi usada na implementacao dos m todos que implementam as instrucoes executadas pelo e interpretador, explorando a heranca de m todos, como ser visto mais adiante. e a 2.4. Valores multiplos Uma caracterstica interessante do Common Lisp e a possibilidade de retornar valores m ltiplos em uma funcao. Isso e similar a retornar uma tupla em outras linguagens e u obter suas componentes por pattern matching, com a diferenca de que, se uma funcao n o espera explicitamente por valores m ltiplos, apenas o primeiro valor e utilizado, e a u os demais ignorados. Por exemplo, a funcao truncate da biblioteca padr o recebe um a n mero real e devolve suas partes inteira e fracion ria como dois valores. Se se deseja u a usar apenas a parte inteira, pode-se usar a funcao em um contexto que n o espera valores a m ltiplos, e apenas a parte inteira ser considerada. u a Valores m ltiplos s o usados extensivamente no programa. u a 2.5. Par metros opcionais e keyword parameters a E possvel denir funcoes com par metros opcionais. Tamb m e possvel denir funcoes a e com keyword parameters, que devem ser passados na forma :nome valor, e em que a ordem dos argumentos n o importa. Finalmente, h rest parametes, que acumulam todos a a os argumentos n o capturados por outros par metros fa funcao. a a 2.6. Escopo din mico opcional a As vari veis globais em Common Lisp s o todas din micas. Isso signica que e possvel a a a criar novas amarracoes dessas vari veis em partes do programa, e todas as funcoes execu a

tadas dentro do escopo din mico dessas amarracoes ver o a amarracao nova, ao inv s da a a e original. O principal uso disso e na manipulacao de entrada e sada: a linguagem permite reamarrar vari veis tais como *standard-output*, redirecionando temporariamente a a sada do programa para uma stream alternativa. Isso e usado na interface gr ca para a capturar a sada do comando print durante a interpretacao de um programa. 2.7. Sistema de condicoes Condicoes s o uma generalizacao de excecoes, em que o uxo do c digo pode voltar do a o tratador para o c digo que invocou o tratador. Uma utilidade disso e usar o sistema de o condicoes para reportar eventos que ocorreram em um ponto mais interno do c digo, sem o interromper sua execucao, e sem a necessidade de carregar o valor atrav s do retorno de e diversas chamadas de funcao. Uma condicao desse tipo e usada na implementacao da interface, como ser visto adiante. Outro uso de condicoes e na criacao de erros cona tinu veis, em que o usu rio pode corrigir um erro e retomar a execucao do programa do a a ponto em que parou. Grande parte dos erros gerados pela linguagem s o continu veis. a a

3. Linguagem implementada
MLP e uma linguagem bastante simples, com uma sintaxe ALGOL-like, e com suporte funcoes de primeira classe. Quando executada com escopo din mico, funcoes retornadas a por outras funcoes formam uma closure capaz de acessar todas as vari veis denidas a no escopo em que a funcao foi criada. Com excecao do operador de atribuicao (que na verdade e um comando), todos os operadores inxados s o funcoes, e podem ser usados a como tal (2+3 e +(2,3) s o ambas express es v lidas). N o h sintaxe para funcoes a o a a a an nimas na vers o atual. o a Indentacao e ignorada pela linguagem. Quebras de linha terminam uma express o, a a menos que a linha termine com um operador inxado. Coment rios s o introduzidos a a pelo caractere #. Os comandos suportados s o: a if teste then corpo-1 [else corpo-2] end Se o teste e verdadeiro, executa corpo-1; caso contr rio, executa corpo-2. a while teste do corpo end Enquanto o teste for verdadeiro, executa corpo. let var = valor Dene uma nova vari vel no escopo corrente. a def nome(arg1, arg2, ...) corpo end Dene uma nova funcao no escopo atual. Na verdade, qualquer express o equiv a alente a uma chamada de funcao pode ser usada no cabecalho, o que inclui tanto chamadas comuns quanto os operadores inxados padr o da linguagem. a var = valor Altera o valor de uma vari vel existente. a return valor Retorna da funcao atual com o valor especicado. Os operadores da linguagem s o, em ordem de preced ncia: + e - un rios; *, / a e a e % (resto da divis o); + e - bin rios; ==, !=, <, <=, >, >=, que podem ser usados tanto a a para n meros quanto para strings; ! (negacao l gica); &&; ||; ,. Os operadores l gicos u o o

tratam 0 como falso, e qualquer outro valor como verdadeiro. Por serem funcoes, esses operadores n o realizam avaliacao curto-circuito. a MLP e uma linguagem dinamicamente tipada. Os unicos tipos de dados suportados pela linguagem s o n meros reais (sem distincao entre inteiros e n meros em ponto a u u utuante), strings e funcoes. Por m, a presenca de closures e da tipagem din mica per e a mitem, de forma indireta, a denicao de tipos de dados complexos. Isso acontece porque um tipo de dados complexo, tal como uma estrutura, e em ess ncia um ambiente de e vari veis. Por exemplo, poderamos denir listas em MLP como: a let nil = 0 # Construtor de listas. def cons(head, tail) def f(x) if x==0 then return head else return tail end end return f end def first(ls) return ls(0) end def rest(ls) return ls(1) end Essa denicao nos permite denir funcoes que manipulam listas, como por exem plo como a map, que aplica uma funcao a todos os elementos de uma lista: def square(x) return x*x end def map(fun, ls) if ls == nil then return nil else return cons(fun(first(ls)), map(fun, rest(ls))) end end let nums = cons(1, cons(2, cons(3, cons(4, nil)))) let squares = map(square, nums)

map(print, squares) Esses exemplos s funcionam quando executados com escopo din mico. o a

4. Implementacao
O interpretador se divide em tr s grandes partes: (1) leitura do c digo a ser interpretado e e o sua transformacao em uma representacao de sua arvore sint tica; (2) convers o da arvore a a sint tica em uma s rie de instrucoes, e posterior interpretacao dessas instrucoes; (3) a ina e terface gr ca. A seguir, ser explicado em detalhes o funcionamento de cada uma dessas a a partes, e ser o destacadas as features da linguagem de implementacao que auxiliaram ou a atrapalharam no desenvolvimento do programa. 4.1. Leitura do c digo o A leitura do c digo comeca com a tokenizacao do c digo-fonte, implementada no pacote o o tokenize. Esse pacote cont m o m todo tokenize, que pode ser chamado tanto com e e uma string quanto com uma stream; se chamado com uma string, uma stream correspon dente e criada com a funcao make-string-input-stream da biblioteca padr o, e a o m todo e reinvocado usando-a. O m todo tokenize l a stream e produz uma lazy e e e list com todas as tokens contidas na stream, lancando uma excecao em caso de tokens inv lidas. a A lazy list e implementada no pacote zlist. Esse pacote dene uma classe zcons, que cont m campos para o primeiro elemento da lista e o resto da lista. O resto e da lista pode ser ou nil (representando uma lista vazia), ou uma outra lista (em geral lazy, mas n o necessariamente), ou uma closure, que, quando executada, produz o restante da a lista. S o denidos dois accessors, zfirst e zrest, para acessar os campos dessa a classe; zrest se encarrega de vericar se o resto da lista e uma closure e, se for o caso, avali -la e substitu-la pelo resultado da avaliacao (de modo que a closure e avaliada uma a unica vez). Uma macro zcons e denida, que permite criar uma lazy list sem a necessidade de criar uma closure explicitamente: a chamada (zcons head tail), an loga a ao construtor cons da linguagem, expande em uma chamada a (make-instance zcons :first head :rest (lambda () tail)); note a presenca do lambda, que posterga a avaliacao de tail at que a closure criada seja invocada. Aqui e e evidente a capacidade que o Common Lisp oferece de estender a linguagem de acordo com a necessidade. Para que haja transpar ncia no uso de lazy lists, e desej vel que se possam usar e a as mesmas funcoes para acessar tanto listas comuns quanto lazy lists. Aqui surge um ponto fraco do Common Lisp: embora ele possua um sistema de orientacao a objetos, ele praticamente n o e usado na biblioteca padr o. As funcoes de acesso a lista n o s o a a a a gen ricas, e portanto n o e possvel fazer sobrecarga das mesmas com m todos adequados e a e para lazy lists diretamente. A solucao empregada e remover as funcoes padr o first, a rest e similares do pacote zlist, e criar m todos novos, gen ricos, que, se chamados e e com listas comuns, chamam as funcoes da biblioteca padr o, mas se chamados com lazy a lists, usam as funcoes do pacote zlist. Isso soluciona parcialmente o problema, mas funcoes escritas em pacotes que n o usem zlist, tais como as da biblioteca padr o, n o a a a

usar o os m todos alternativos, o que signica que n o podemos usar as construcoes de a e a iteracao padr o com lazy lists, por exemplo. Al m disso, sempre que se importa o pacote a e common-lisp e o zlist em um mesmo pacote, e necess rio resolver explicitamente a o conito de nomes que resulta do fato de ambos denirem first e rest. Adicionalmente, os m todos novos denidos para as listas padr o lancam uma e a excecao caso se tente acessar o primeiro elemento ou o restante da lista vazia, mudando o comportamento padr o do Common Lisp de retornar nil (a pr pria lista vazia) nesses a o casos. Embora muitas vezes o comportamento padr o seja desejado, em particular na a manipulacao de listas que representam c digo, isso oculta diversos erros e leva a bugs o obscuros, o que prejudica a robustez da linguagem. O resultado da tokenizacao e usado no parsing, que converte tokens em estruturas representando a arvore sint tica do programa. Essas estruturas s o denidas no pacote a a expr; as rotinas de parsing, em parse. Todas as rotinas de parsing devolvem dois valores: a express o resultante da etapa de parsing que realizam, e o restante da lista de a tokens. Esses valores s o capturados pela forma multiple-value-bind. A unica a excecao e a rotina parse-program, que faz o parsing do programa inteiro, e, por denicao, n o pode deixar sobrar parte dos tokens; se ao nal de sua execucao nem todo a token foi consumido, uma excecao e lancada. Em parse, mais uma extens o sint tica e usada. De maneira similar ao que acona a tece em C, em Common Lisp n o e possvel usar uma forma case para comparar strings, a pois strings s s o consideradas eql (o teste de igualdade padr o) se elas representarem o a a o mesmo objeto. Para contornar esse problema na funcao parse-statement, e denida uma nova forma, case-equal, que usa equal ao inv s de eql como teste de e comparacao (duas strings s o equal se possuem os mesmos caracteres). Essa forma e a denida no pacote util, juntamente com outras funcoes e macros auxiliares. 4.2. Interpretacao O resultado do parsing e convertido em uma s rie de instrucoes a serem executadas pelo e interpretador. Os diversos tipos de instrucao s o denidos como classes que herdam de a uma classe comum instruction. Al m de permitir heranca de c digo, isso permite e o especializar os m todos do interpretador pelo tipo da instrucao, com um resultado an logo e a a um casamento de padr es. A compilacao gera instrucoes para cada bloco de comandos o presente no c digo, e cria objetos representando as funcoes denidas no c digo. Os o o pacotes envolvidos nesse processo s o compile e mlp-objects. a O pacote interpret cont m as funcoes de interpretacao. Ele dene a classe e interpreter, que cont m um campo que indica se o tipo escopo a ser usado na e execucao e est tico ou din mico, e uma lista de frames de execucao. Cada frame cont m a a e um vetor de instrucoes, um ndice que diz qual a pr xima instrucao a ser executada, um o ponteiro para seu pai est tico, uma lista de amarracoes de vari veis, uma ag indicando se a a o frame pertence a uma funcao ou n o, uma pilha de argumentos usada internamente pelo a interpretador para passagem de par metros entre instrucoes, e o nvel do bloco na pilha a (usado apenas para exibicao). Todo bloco do c digo original gera um frame de execucao, o incluindo o corpo de ifs e whiles. Isso facilita a implementacao dessas construcoes, e permite que vari veis sejam denidas com escopo apenas dentro do corpo desses comana dos.

O m todo prepare-to-run recebe um objeto interpreter, uma string e representando o c digo, e cria um frame inicial para o interpretador, contendo o vetor o de instrucoes correspondente ao c digo passado e amarracoes dos identicadores padr o o a da linguagem (operadores inxados e a funcao print). O m todo mlp-step realiza e um passo de execucao. As diversas instrucoes s o implementadas pela funcao gen rica a e interpret, que recebe o interpretador, o frame de execucao atual e a instrucao a ser executada. Essa funcao e especializada para cada tipo de instrucao de modo a implementar seu comportamento. As diversas instrucoes podem ter efeitos tais como empilhamento de valores na pilha de argumentos do frame, amarracao de uma vari vel ao valor contido no a topo dessa pilha, acesso a vari veis, chamadas de funcao e conseq ente criacao de novos a u frames, criacao de closures, entre outras. 4.3. Interface A interface, contida no pacote gui, e implementada atrav s da classe e gui-interpreter, que herda de interpreter, adicionando campos correspondentes aos objetos presentes na interface. Essa interface permite tanto executar o c digo do comeco ao m, quanto realizar uma execucao passo-a-passo do c digo. o o A funcao gen rica interpret e re-especializada para a classe e gui-interpreter e para os tipos de instrucoes relevantes para, al m de re e alizarem a operacao de interpretacao, alterarem os objetos na interface de modo a reetir os efeitos da instrucao. Aqui foi vantajoso poder especializar um m todo no tipo de e m ltiplos argumentos. u Al m disso, como n o h uma correspond ncia um-para-um entre os passos da e a a e interface e os passos do interpretador (que podem ser de uma granularidade pequena demais para serem interessantes), apenas alguns tipos de instrucao levam ao t rmino de um e passo. Para isso, o m todo interpret e mais uma vez especializado para a classe e gui-interpreter, mas sem especializar em nenhum tipo particular de instrucao; nesse m todo testa-se se o tipo da instrucao faz parte de uma lista de m todos que termie e nam a execucao, usando para isso a forma typecase, que realiza um tipo de reex o so a bre o tipo do objeto. Se for o caso, uma condicao end-step e sinalizada. Essa condicao n o encerra a execucao do m todo, mas e tratada na funcao chamadora, gui-step, de a e modo de que depois do t rmino da execucao do m todo, a gui-step ter conhecimento e e a de que deve encerrar. Note que, para cada combinacao de objetos interpretador e instrucao, diversos m todos s o aplic veis, com diferentes graus de especicidade. A linguagem ordena os e a a m todos por especicidade, e executa-os do mais especco ao mais gen rico, sempre que e e um m todo mais especco faz uma chamada a call-next-method (similar a super e em Java). O fato de que diversos m todos s o executados para a mesma funcao gen rica e a e ` torna complicada a passagem da informacao de t rmino de passo a gui-step, pois os e m todos da classe original interpreter n o t m conhecimento dessa informacao. e a e Uma diculdade com o uso de multim todos foi que as regras para determinacao e de especicidade tratam os par metros da esquerda para a direita, tratando um m todo a e ` com par metro a esquerda especializado como mais especco do que outro que esa pecialize em uma superclasse mais gen rica, independentemente da especicidade e dos par metros restantes. Embora seja um comportamento coerente, isso exigiu a a

alteracao posterior dos m todos do pacote interpret, para receberem o interpre e tador como primeiro argumento ao inv s de ultimo, de modo que a os m todos de e e gui-interpreter fossem tratados como mais especcos do que os m todos equiva e lentes de interpreter.

5. An lise da linguagem a
O desenvolvimento de uma aplicacao de m dio porte permitiu a observacao direta das e vantagens e desvantagens da linguagem de implementacao. A seguir, apresentaremos uma an lise do Common Lisp segundo os crit rios para an lise de linguagens vistos no a e a decorrer da disciplina. Ser atribudo um valor de 0 a 10 a cada crit rio analisado, segundo a e o grau em que a linguagem o satisfaz. Simplicidade: 5 Como mencionado anteriormente, o Common Lisp surgiu como uma uni o das a variantes de Lisp existentes na d cada de 1980, e agrega diversas funcionalidades e desses dialetos. Nesse sentido, pode-se dizer que a linguagem n o e particulara mente simples, e de fato possui uma quantidade not vel de features: escopos a est tico e din mico, uma vasta colecao de tipos de dados, incluindo hash tables, a a arrays, vetores de bits, n meros racionais e complexos de precis o arbitr ria, e u a a um sistema de orientacao a objetos notavelmente complexo. Por m, a linguagem e em certos aspectos e bastante mais simples do que muitas linguagens usuais: ela ` possui apenas 25 operadores especiais (an logos as palavras reservadas de outras a linguagens), sendo todas as outras construcoes sint ticas denidas na biblioteca a padr o atrav s de macros; a sintaxe segue o formato uniforme de listas em que o a e primeiro elemento determina a funcao ou forma chamada; entre outras. O Common Lisp e notado como complexo em particular quando comparado com o Scheme. Por m, o fato de a linguagem possuir uma riqueza maior de recure sos disponveis tende a tornar o c digo mais port vel, pois pode-se realizer uma o a grande quantidade de tarefas sem a necessidade de bibliotecas externas. Esse e um dos principais problemas pr ticos com o Scheme, em que qualquer programa a de tamanho moderado acaba usando extens es fornecidas pela implementacao e o n o cobertas pelo padr o da linguagem a a Expressividade: 9 A presenca de macros permite estender a linguagem indenidamente, permitindo a criacao de construcoes que representem melhor representem o problema a ser resolvido. E comum em Lisp criar Domain Specic Languages embutidas na linguagem, atrav s de macros. Novas construcoes, tais como pattern matching, e podem ser adicionadas em alteracao da implementacao da linguagem. Isso d ao a Common Lisp uma expressividade muito maior do que a de linguagens convencionais. Um aspecto em que o Common Lisp deixa a desejar em termos de exibilidade e em seu sistema de tipos. Embora a linguagem permita algumas declaracoes de tipo, primariamente com o objeto de auxiliar o compilador a gerar c digo mais o eciente, e na especializacao de m todos, nem sempre e possvel declarar um e tipo especco o suciente, em particular pela falta de tipos param tricos. Por e exemplo, e possvel especicar o tipo lista, mas n o lista de inteiros. a

Ortogonalidade: 7 Em alguns aspectos, a linguagem apresenta uma ortogonalidade not vel: a sintaxe a uniforme; n o h diferenca observ vel entre os operadores especiais da linguagem a a a e macros denidas pelo usu rio; funcoes aritm ticas em geral funcionam com a e quaisquer tipos de n meros; operacoes que resultam em n meros complexos s o u u a tratadas adequadamente (e.g., raiz quadrada de n meros negativos); funcoes de u seq encia funcionam com vetores, listas e strings; todos os valores s o objetos, e u a pode-se criar m todos novos sobre os tipos padr o; entre outras. e a Em outros aspectos, a linguagem apresenta falta de ortogonalidade: convencoes de passagem de par metros e inidicacao de falha variam de funcao para a funcao (e.g., algumas retornam nil, outras retornam dois valores, o segundo indicando sucesso ou falha); funcoes com comportamento gen rico da bib e lioteca padr o (e.g., +, length) n o s o generic functions, e n o podem a a a a ser especializadas; nomenclatura com estilo inconsistente (e.g., rplaca vs. multiple-value-bind). Alguns desses itens t m origem no fato de o Come mon Lisp ter se baseado em diversos dialetos de Lisp, com convencoes incom patveis entre si. Sintaxe amig vel: 6 a A sintaxe do Lisp e bastante n o-familiar para a maior parte dos programadores, e a e praticamente impossvel de usar sem um editor de texto com suporte adequado (com parenthesis matching e indentacao autom tica). Com um editor apropriado, a tende-se a se guiar pela indentacao do c digo ao inv s dos par nteses, e esse o e e problema e bastante reduzido. Redigibilidade: 10 Ap s familiarizar-se com a linguagem, dada a expressividade e exibilidade proo porcionadas pelas macros e pela tipagem din mica, e possvel escrever c digo em a o Common Lisp com facilidade. O suporte a funcoes de primeira classe tamb m e permite reduzir a quantidade de c digo necess ria, pois e possvel escrever proo a cedimentos gen ricos, com lacunas no comportamento que s o providas por e a um par metro funcional. A grande quantidade de funcoes de manipulacao de lisa tas favorece seu uso para prototipacao de aplicacoes. O fato de se poder chamar funcoes diretamente pelo prompt da linguagem, sem necessidade de denir um ` programa principal, ajuda a testar o c digo a medida em que e escrito, facilitando o o desenvolvimento. Legibilidade: 7 Ler c digo em Common Lisp requer uma familiaridade com a linguagem maior o ` do que com a maior parte das linguagens convencionais, devido a sintaxe peculiar e ao fato de o Lisp, ao contr rio da maior parte das linguagens modernas, n o ser a a ` um descendente do ALGOL, e possuir uma longa cultura a parte das linguagens ALGOL-like. Ap s a habituacao, ler c digo escrito por outras pessoas n o e, em o o a geral, difcil. H um potencial para problemas de legibilidade no fato de que a a sintaxe da linguagem pode ser arbitrariamente modicada, mas e regra geral entre programadores Lisp que macros s devem ser usadas quando funcoes n o podem o a realizar a mesma tarefa com igual clareza, e no geral o uso cuidadoso de macros acaba aumentando a legibilidade do c digo, abstraindo detalhes desnecess rios. o a Tamanho de c digo: 9 o Embora o Common Lisp possa dar uma impress o de verbosidade, devido ao a

seu uso freq ente de identicadores longos (e.g., multiple-value-bind, u with-open-file) e ao uso extensivo de keyword parameters, em geral o n mero de elementos (e n o caracteres) necess rios para escrever um programa u a a e menor em Common Lisp do que em uma linguagem convencional. Em particular, a presenca de macros, garbage collection, e o fato de declaracoes de tipos serem opcionais contribui para a reducao do tamanho de c digo. Por m, a rela o e tiva falta de bibliotecas disponveis para a linguagem, em especial quando com parada com linguagens de script, tais como Python e Ruby, acaba exigindo mais codicacao do que em uma dessas linguagens. Quando existe uma preocupacao com eci ncia, o c digo pode acabar cando bastante maior, devido ao acr scimo e o e de declaracoes de tipo e a denicao de estruturas especcas para o problema, ainda que o c digo resultante seja em geral menor do que em uma linguagem o compilada convencional. Escalabilidade: 8 E possvel escrever um prot tipo de uma aplicacao, obtendo-se assim uma vers o o a inicial funcional, e modic -lo progressivamente melhorando sua performance a e robustez, levando assim a uma aplicacao nal. A presenca de heranca e polimorsmo permite muitas vezes estender a funcionalidade de um programa sem alteracoes do c digo existente. A presenca de reexividade tamb m contribui o e para adaptacao de programas para novos problemas com alteracoes pequenas. Portabilidade: 8 ` Um programa que se restrinja as funcionalidades da biblioteca padr o ser altaa a mente port vel, pois o Common Lisp e denido por um padr o ANSI, ao qual a a a maior parte das implementacoes adere. Devido ao fato de a biblioteca padr o a ser bastante extensa, e possvel escrever aplicacoes port veis de grande porte. Ao a se usar bibliotecas de terceiros, por m, a portabilidade cai bastante, pois estas e freq entemente dependem de recursos especcos de implementacao (e.g., meios u para chamar funcoes do sistema operacional). Conabilidade, robustez: 7 Common Lisp e uma linguagem com tipagem din mica e com late binding, e a portanto diversos erros s o detectados somente durante a execucao do programa, a o que reduz a conabilidade dos programas. Os compiladores, com diferentes graus de cobertura, s o capazes de gerar warnings para certos tipos de erros (o a SBCL, por exemplo, e capaz de inferir os tipos de diversas express es, e emite o avisos quando o tipo inferido conita com seu uso). Por essa raz o, e comum a fazer unit testing extensivo de aplicacoes e bibliotecas. Por outro lado, a presenca de erros continu veis faz com que seja possvel corrigir a ` erros a medida em que s o encontrados, o que pode ser importante em aplicacoes a crticas, que n o devem ser interrompidas. Al m disso, a menos que o compi a e lador seja explicitamente informado de que o c digo deve ser compilado sem o vericacoes de seguranca, erros tais como acesso al m dos limites de um vetor, e ou erros de tipo, s o devidamente detectados e informados ao usu rio. Essas cara a actersticas contribuem para a conabilidade da linguagem. Reusabilidade: 10 Como mencionado anteriormente, paradigma funcional favorece o reuso de c digo, permitindo a criacao de rotinas gen ricas cujas lacunas s o preenchidas o e a por um par metro funcional. Al m disso, o suporte a orientacao a objetos, com a e

heranca e polimorsmo, contribui para o reuso de c digo. A tipagem din mica o a permite que as mesmas estruturas de dados sejam usadas para conter dados de tipos diferentes. Abstracao de dados e processos: 10 Para abstracao de dados, a linguagem prov estruturas e classes, com todos os e recursos oferecidos pela orientacao a objetos. Para abstracao de procedimentos, a linguagem prov funcoes de primeira classe, que permitem tratar procedimentos e como valores na execucao do programa. Estruturas de controle: 10 Al m de fornecer uma rica variedade de estruturas de controle, incluindo retornos e n o-locais, excecoes e condicoes, funcoes de alta ordem para iteracao e reducao a de listas, e a macro loop, que prov uma mini-linguagem pr pria para controle de e o laco, a linguagem oferece macros, que permitem criar novas estruturas de controle segundo a necessidade. Familiaridade: 6 Um dos componentes do grupo nunca tinha usado a linguagem antes; o outro j a a conhecia h quase um ano, mas nunca tinha escrito um programa do porte do a desenvolvido neste trabalho. Ambos tinham alguma familiaridade com Scheme, devido a seu uso no curso. Como explicado anteriormente, devido ao fato de o Common Lisp n o ser um descendente de ALGOL e possuir um desenvolvia mento paralelo mais ou menos independente, a linguagem e bastante n o-familiar a ` a primeira vista.

6. Conclus o a
No trabalho tivemos a oportunidade de aplicar na pr tica os crit rios para avaliacao de lina e guagens vistos em aula, utilizando uma linguagem n o-mainstream. Podemos observar a que diferentes linguagens fazem diferentes trade-offs na priorizacao de crit rios coni e tantes (e.g., simplicidade vs. redigibilidade e portabilidade, ortogonalidade vs. compat ibilidade e performance). Nesse sentido e interessante comparar o Common Lisp com o Scheme, uma linguagem que faz muitos dos trade-off contr rios aos do Common Lisp, a preferindo manter a linguagem extremamente simples e ortogonal, mas quebrando compatibilidade com os Lisps anteriores e tornando a escrita de aplicacoes maiores freq en u temente dependende de extens es. o ` Por falta de tempo, e devido a documentacao incompleta da biblioteca gr ca a utilizada, a interface n o foi desenvolvida a ponto de ser considerada completa, possuindo a um aspecto relativamente rudimentar, ainda que funcional.

Refer ncias e
McCarthy, John (1960). Recursive functions of symbolic expressions and their computation by machine, Part I. Steele, Jr., Guy L. (1990). Common Lisp: the language (2nd ed.). Digital Press, Newton, MA, USA. Gerald Jay Sussman and Guy Lewis Steele, Jr. Scheme: An Interpreter for Extended Lambda Calculus. MIT AI Lab. AI Lab Memo AIM-349. December 1975.

Richard P. Gabriel, Kent M. Pitman (1988). Technical Issues of Separation in Function Cells and Value Cells. Lisp and Symbolic Computation, Volume 1, No. 1, June 1988, pp81-101.

Vous aimerez peut-être aussi