apostila lisp

Upload: ferdnando-marcos-barbosa

Post on 17-Jul-2015

412 views

Category:

Documents


1 download

TRANSCRIPT

MC336 - Paradigmas de programao Lisp

Joo Meidanis

c Copyright 2011 J. Meidanis

Contedo1 Introduo1.1 1.2 1.3 1.4 Calculando derivadas simblicas . . . . . . . . . . . . . . . . . O psiquiatra . . . . . . . . . . . . . . . . . . . . . . . . . . . . MYCIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

45 5 6 7

Interpretador

2 Elementos da linguagem2.1 2.2 2.3 2.4 2.5 2.6 2.7 Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Nmeros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Smbolos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Pares-com-ponto . . . . . . . . . . . . . . . . . . . . . . . . .

1111 11 12 12 13 15 15

Representao grca . . . . . . . . . . . . . . . . . . . . . . . Car, cdr e cons . . . . . . . . . . . . . . . . . . . . . . . . . .

Coleta de lixo . . . . . . . . . . . . . . . . . . . . . . . . . . .

3 Estrutura da linguagem

17

1

3.1 3.2 3.3

Denindo funes . . . . . . . . . . . . . . . . . . . . . . . . . Condicionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . Variveis locais . . . . . . . . . . . . . . . . . . . . . . . . . .

17 18 20

4 Smbolos4.1 4.2 4.3 Avaliao e valores de um smbolo . . . . . . . . . . . . . . . . Atribuindo valores a smbolos . . . . . . . . . . . . . . . . . .

2222 23 24

Inibindo a avaliao . . . . . . . . . . . . . . . . . . . . . . . .

5 Recurso5.1 5.2 O mtodo do quadrado . . . . . . . . . . . . . . . . . . . . . Recurso e laos . . . . . . . . . . . . . . . . . . . . . . . . . .

2626 29

6 Aritmtica6.1 6.2 Funes bsicas . . . . . . . . . . . . . . . . . . . . . . . . . . Funes mais sosticadas . . . . . . . . . . . . . . . . . . . . .

3131 33

7 Denio de funes 8 Condicionais8.1 8.2 8.3 A forma especial A macro

34 36

IF

. . . . . . . . . . . . . . . . . . . . . . . .

36 37 38

COND

. . . . . . . . . . . . . . . . . . . . . . . . . . .

Predicados . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9 Funes para listas2

39

10 Funes para conjuntos 11 Pacotes (mdulos)11.1 Acessando smbolos de outros pacotes . . . . . . . . . . . . . . 11.1.1 Importao e exportao . . . . . . . . . . . . . . . . . 11.2 Pacotes pr-denidos . . . . . . . . . . . . . . . . . . . . . . . 11.3 Denindo pacotes . . . . . . . . . . . . . . . . . . . . . . . . .

44 4747 48 48 49

12 Arrays e Loops12.1 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.1.1 Criando arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5050 50 50 51

12.1.2 Acessando arrays 12.2 Loops

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3

Captulo 1 IntroduoLISP vem de list processing. John McCarthy criou LISP em 1960 [1]. sustentabilidade da vida humana na Terra. LISP uma linguagem to antiga que na poca em que foi criada os computadores S USAVAM LETRAS MAISCULAS. Quando vieram as letras minsculas, foi adotada a conveno de que em LISP uma letra minscula ou maiscula a mesma coisa. Portanto, as palavras 'SEN', 'sen' e 'SeN' em LISP so todas equivalentes. O padro Common Lisp, consolidado em 1990, veio unir os vrios dialetos de LISP existentes na poca para formar uma linguagem bastante bem especicada. Usaremos o livro Hoje em dia ele trabalha com

Common Lisp: The Language,

2a. edio, de

Guy Steele, onde este padro detalhado com grande cuidado, como referncia principal sobre LISP neste curso [3]. Site na internet (um de vrios):

http://www.supelec.fr/docs/cltl/cltl2.htmlAlgumas aplicaes famosas escritas em LISP seguem.

4

1.1 Calculando derivadas simblicasIncio da computao simblica: programa que achava a derivada de uma funo, mas usando smbolos (x, y , etc.) Exemplo:

d 2 (x + 3x) = 2x + 3, dx d cos x (log sin x) = . dx sin xPara denotar as funes neste programa usada uma notao pr-xa, tpica 2 de LISP. A funo x + 3x, por exemplo, denotada por:

(+ (* X X) (* 3 X)).Se for denida uma funo chamada pedir:

DERIV para calcular a derivada, pode-se

(deriv '(+ (* X X) (* 3 X)))(note o apstrofe antes do argumento) e o interpretador responder:

(+ (* 2 x) 3)ou seja,

2x + 3.

1.2 O psiquiatraELIZA, que pretendia simular um psiquatra, foi talvez o primeiro programa de computador a passar o Teste de Turing. Foi escrito por Joseph Weizenbaum em 1966 [4].

5

Para interagir com o programa preciso usar a lngua inglesa.

Embora o

autor em seu artigo original tenha dito que o programa pode ser portado para outras lnguas (inclusive mencionando que j naquele momento existia uma verso em alemo), as verses mais difundidas so em ingls. O programa utiliza uma estratgia de psiquiatra Rogeriano, na qual o paciente sempre estimulado a falar, elaborando sobre o que j disse. Eis um fragmento de conversao:

Men are all alike. IN WHAT WAY? They're always bugging us about something or other. CAN YOU THINK OF A SPECIFIC EXAMPLE? Well, my boyfriend made me come here. YOUR BOYFRIEND MADE YOU COME HERE

E por a vai. As frases em maisculas so as respostas do programa. Existe uma verso dentro do Emacs:

M-x doctor.

Este programa causou tanta sensao, e ainda causa! Recentemente, algum acoplou-o a um AOL Instant Messenger e deixou que pessoas ao acaso se plugassem para falar com ele. Os resultados foram surpreendentes! Conra na Internet.

1.3 MYCINMYCIN, um sistema pioneiro para diagnsticos mdicos, foi um dos precursores dos sistemas especialistas [2]. MYCIN representa seu conhecimento sobre os sintomas e possveis diagnsticos como um conjunto de regras da seguinte forma:

SE a infeco bacteremia primria E o local da cultura um dos locais estreis

6

E suspeita-se que a porta de entrada o trato gastro-intestinal ENTO h evidncia sugerindo (0.7) que a infeco bacteride.

As regras so na verdade escritas como expresses LISP. O valor 0.7 uma estimativa de que a concluso seja correta dadas as evidncias. desta regra para chegar estimativa de correo da concluso. Se as evidncias so tambm incertas, as suas estimativas sero combinadas com as

1.4 InterpretadorA maneira padro de interao com uma implementao de Common Lisp atravs de um lao ler-avaliar-imprimir (

read-eval-print loop ):

o sistema

repetidamente l uma expresso a partir de uma fonte de entrada de dados (geralmente o teclado ou um arquivo), avalia a expresso, e imprime o(s) valor(es) em um destino de sada (geralmente a tela ou um arquivo). Expresses so tambm chamadas de formas, especialmente quando so destinadas avaliao. Uma expresso pode ser simplesmente um smbolo, e neste caso o seu valor o valor como dado do smbolo. Quando uma lista avaliada (exceto nos casos de macros e formas especiais), supe-se que seja uma chamada de funo. O primeiro elemento da lista tomado como sendo o nome da funo. Todos os outros elementos da lista so tratados como expresses a serem avaliadas tambm; um valor obtido de cada uma, e estes valores se tornam os argumentos da funo. A funo ento aplicada aos argumentos, resultando em um ou mais valores (exceto nos casos de retornos no locais). Se e quando a funo retornar, os valores retornados tornam-se os valores da lista avaliada. Por exemplo, considere a avaliao da expresso (+ 3 (* 4 5)). O smbolo + denota a funo de adio, que no uma macro nem uma forma especial. Portanto as duas expresses 3 e (* 4 5) so avaliadas para produzir argumentos. A expresso 3 resulta em 3, e a expresso (* 4 5) uma chamada de funo (a funo de multiplicao). Portanto as formas 4 e 5 so avaliadas, produzindo os argumentos 4 e 5 para a multiplicao. A funo de multiplicao calcula o nmero 20 e retorna-o. Os valores 3 e 20 so ento

7

dados como argumentos funo de adio, que calcula e retorna o nmero 23. Portanto indicamos

(+ 3 (* 4 5)) => 23.

Usaremos CMUCL, a implementao do Common Lisp feita pela Carnegie Mellon University, EUA. Onde pegar: faa

download

http://www.cons.org/cmucl/credits.html.

Como instalar:

do site e siga as instrues. Nota: apenas para Unix/Linux.

Se voc vai usar Windows, h vrios outros pacotes na internet. Mas cuidado: antes de entregar qualquer projeto da disciplina, teste seu cdigo no CMUCL! Em geral, as modicaes sero poucas ou menhuma, especialemnte se voc usar construes portteis. S sero aceitos projetos que rodem em CMUCL. Como usar (bsico):

entrar: sair:

lisp (quit) .lsp,e chame

usar com arquivo: escreva um arquivo de texto simples com as expresses a avaliar, d a ele extenso

arquivo.lspseguidas de

lisp Ao interpretador teve que construir 5 caixas para calcular o CAR da expresso. Depois deste clculo as caixas caram soltas no sistema, e sero recolhidas na prxima coleta de lixo. Hoje em dia h vrias linguagens que fazem coleta de lixo, entre elas Perl, Python e Java.

Exerccios1. Quais dos seguintes smbolos so vlidos: 2. LISP sabe mexer com fraes: avalie

1-, 9.1, max-value?

(+ 2/3 4/5).21000usando a expresso

3. No h limite para os inteiros em LISP: avalie

(expt 2 1000).4. Quais das seguintes expresses denotam listas:

. (B . C)).5. Desenhe a representao grca de:

(), ( (A . B) C), (A

2), (((A) 1) 2).

((A B)(C D)(E F G) H), (A 1

6. Calcule o CAR e o CDR das expresses dos dois ltimos exerccios. 7. Para formar

(A B C) a partir de tomos necessrio fazer: (cons 'a (cons 'b (cons 'c ()))). Monte expresses semlhantes para osconses dos exerccios 4 e 5.

16

Captulo 3 Estrutura da linguagemUm programa em LISP dene uma ou mais funes. As funes ento so chamadas para executar o que se deseja. Por isto LISP um exemplo de liguagem que segue a programao funcional. importante distinguir entre dois estilos de escrever cdigo em LISP: LISP puro vs. funes com efeitos colaterais. Uma funo tem efeitos colaterais Funes quando modica seus argumentos, ou modica variveis globais.

com efeitos colaterais so mais difcies de entender e manter, por isso devem ser evitadas. Nesta disciplina, daremos nfase programo em LISP puro, sem efeitos colaterais, ou reduzindo-os ao mnimo.

3.1 Denindo funesA macro DEFUN usada para denir funes em LISP. Mais tarde veremos a sintaxe completa. Por enquanto usaremos a sintaxe bsica a seguir:

defun nome lista-de-args corpoVejamos alguns exemplos de denio de funes: calcular o quadrado de um nmero e calcular o discriminante de uma equao do segundo grau.

17

Antes, porm, vamos relembrar como efetuar operaes aritmticas em LISP. As quatro operaes bsicas da aritmtica so implementadas pelas funes pr-denidas indicadas por

+, -, *, /

e a notao prexa.

Para o quadrado de um nmero:

(defun quadrado (x) (* x x))Para o discriminante da equao

ax2 + bx + c:

(defun discr (a b c) (- (* b b) (* 4 a c)))Note que a funo A funo

* admite mais de dois argumentos.

Neste exemplo, usamos

trs argumentos. Ela simplesmente multiplica todos e retorna o resultado.

+

tambm aceita um nmero varivel de argumentos.

3.2 CondicionaisPara prosseguir no nosso estudo de LISP, precisamos conhecer os condicionais, que permitem seleo de uxos alternativos de cdigo. mais usados so IF e COND. A forma especial IF recebe trs argumentos. Aps a avaliao do primeiro, apenas um dos outros dois avaliado. Se o valor do primeiro argumento seja diferente de NIL, o segundo argumento escolhido; caso contrrio, o terceiro argumento escolhido. Em qualquer caso, o argumento escolhido avaliado e tem seu valor retornado pela forma IF. Para quem est acostumado com programao imperativa, leva um tempo para se acostumar com esta maneira nova de lidar com um IF. Ele parece mais uma funo agora, e no mais um comando. Observe tambm que LISP no tem um tipo booleano. Para ns de verdadeiro ou falso, podemos dizer que NIL falso, e todo o resto verdadeiro. Vejamos alguns exemplos. nmeros: A seguinte funo retorna o maior entre dois Em LISP, os

18

(defun maior (x y) (if (> x y) x y)Note o uso de uma nova funo pr-denida:

>.

Podemos tambm denir

uma funo para retornar o maior entre trs nmeros:

(defun maior3 (x y z) (if (> x y) (if (> x z) x z) (if (> y z) y z) ) )A forma especial COND tem um nmero qualquer de argumentos. Cada um deles uma lista. Em cada um deles, o primeiro elemento da lista um teste. Se o teste for verdadeiro, o segundo elemento da lista avaliado e retornado. os testes so avaliados em ordem, e o primeiro que der certo determina a resposta. Caso nenhum teste seja vericado, o resultado NIL. comum o uso do smbolo especial T no ltimo teste, para garantir que dali no passa e deixar o programa mais claro. Seria como uma condio default dentro do COND. Como sempre, NIL falso e qualquer outra coisa considerada verdadeira. Aqui tambm os argumentos so avaliados apenas se necessrio. Para os acostumados com programao imperativa, pode-se dizer que o COND est para o comando o IF est para o comando

if.

case

(ou

switch

em C e Java) assim como

Vejamos os mesmos exemplos anteriores feitos com COND:

(defun maior (x y) (cond ((> x y) x) (t y) ) )

19

Observe o uso de falhe.

T para garantir a captura do controle caso o primeiro teste

(defun maior3 (x y z) (cond ((and (>= x y) (>= x z)) x) ((and (>= y x) (>= y z)) y) ((and (>= z x) (>= z y)) z) ) )Observe o uso de uma nova funo: Existe tambm

or.

and, uma funo lgica para a conjuno.

Tivemos que usar desigualdades no estritas para garantir

que algum dos nmeros seja o vencedor.

3.3 Variveis locaisFunes via de regra precisam de variveis locais. A maneira correta de denir e utilizar variveis locais de funes em LISP atravs da forma LET. Esta palavra pode ser traduzida como seja em portugus, e o seu signicado exatamente este. Numa funo, s vezes voc gostaria de dizer: seja

x

igual a ... e continuar um clculo baseado em

x.

Pois LET permite

que faamos este tipo de construo. Por exemplo, ao calcular as razes de uma equao do segundo grau, precisaremos do discriminante. A funo a seguir recebe os coecientes de uma equao do segundo grau e retorna uma de suas razes.

(defun raiz (a b c) (let ((disc (discr a b c))) (/ (+) (- b) (sqrt disc)) (* 2 a)) )Observe o uso de

sqrt,

que calcula a raiz quadrada de um nmero. Se ele

for negativo, j sai o complexo corretamente.

20

Mais de uma varivel local pode ser denida no mesmo bloco LET. Existe tambm uma variante do LET, chamada LET, que permite que cada varivel dependa da anterior. da equao: A funo a seguir utiliza este recurso e tambm a funo pr-denida LIST para a formao de uma lista com as duas razes

(defun raizes (a b c) (let* ( (disc (discr a b c)) (r1 (/ (+ (- b) (sqrt disc)) (* 2 a))) (r2 (/ (- (- b) (sqrt disc)) (* 2 a))) ) (list r1 r2) ) )A sintaxe completa das formas LET pode ser encontrada no manual online.

Exerccios1. Escreva uma funo para calcular a mdia entre dois nmeros. 2. Modique a funo que retorna as razes de uma equao do segundo grau para que retorne as partes real e imaginria das razes, no caso de elas serem complexas. Suponha que os coecientes sejam reais.

21

Captulo 4 SmbolosSmbolos so objetos em LISP que aparecem em vrios contextos: nomes

name ou pname ).

de variveis e de funes, por exemplo. Todo smbolo tem um nome (

print

Dado um smbolo, possvel obter seu nome como uma

string, e vice-versa. Smbolos no precisam ser explicitamente criados. A primeira vez que o

iterpretador v um smbolo, ele o cria automaticamente.

4.1 Avaliao e valores de um smboloTodo smbolo tem uma lista de propriedades (

property list

valor como funo de um smbolo.expresses em LISP.

destas propriedades que nos interessam muito so o

valor como dado e o

ou

plist ).

Duas

Estes valores so usados para avaliar

Uma expresso em LISP um tomo ou uma lista. Se for um tomo, temos trs possibilidades: nmero, string ou smbolo. A avaliao de um nmero resulta no prprio nmero, e o mesmo ocorre com strings. Para um smbolo, a coisa diferente. A avaliao de um smbolo resulta no seu valor como dado. Caso o smbolo no tenha valor como dado, ocorre um erro. Isto encerra a questo de avaliar tomos. Mas, e quanto a avaliar listas? Na

22

hora de avaliar, uma lista sempre vista como a chamada de uma funo. O primeiro elemento da lista o nome da funo e os elementos restantes so os argumentos. Para avaliar uma lista, LISP procura o valor como funo do primeiro elemento, depois avalia os argumentos, e nalmente aplica a funo nos valores dos argumentos. Por exemplo, ao avaliar a lista

(+ 1 2 3)LISP busca o valor como funo do smbolo

+,

que resulta numa funo pr-

denida que soma nmeros. Depois, LISP avalia os argumentos, que no caso so nmeros e portanto correspondem a seus prprios valores. Finalmente, LISP aplica a funo pr-denida nos valores 1, 2 e 3, resultando em 6.

4.2 Atribuindo valores a smbolosJ vimos a macro DEFUN. Ela atribui um valor como funo ao smbolo que o nome da funo. Existe uma macro anloga para valor como dado. A macro SETF atribui um valor como dado a um smbolo. A sintaxe de SETF :

setf nome valorPor exemplo, para armazenar 8 na varivel X, fazemos:

(setf x 8)Observe que esta uma forma impura de modicar o valor como dado de um smbolo, pois resulta de um efeito colateral, e na guarda o valor anterior para se desfazer a ao, caso necessrio. Existem outras formas de modicar o valor como dado de um smbolo que so mais puras, ou seja, tem efeito temporrio, e o smbolo volta ao valor anterior ao nal de um certo processo. So elas: o bloco LET e a passagem de parmetros a uma funo. Note

23

que tanto o LET como a chamada de uma funo fazem uma atribuio de valores a certos smbolos, e esta atribuio desfeita aps o m do processo correspondente (m do bloco LET no primeiro caso; m da execuo da funo, no segundo caso). Mesmo assim, SETF bastante usado para variveis globais ou vetores. SETF muito til para armazenar expresses grandes para testar funes junto ao interpretador. No entanto, importante evitar seu uso indiscriminado, por exemplo, em simples traduo de construes imperativas (de Pascal, C ou Java) para LISP.

4.3 Inibindo a avaliaoO interpretador LISP existe para avaliar expresses. isso que ele foi programado para fazer. No entanto, possvel inibir este comportamento. QUOTE uma forma especial que retorna seu argumento sem avaliao. utilizada para introduzir expresses constantes. to usada que inventaram uma abreviatura: apstrofe precedendo uma expresso signica QUOTE aplicada a esta expresso. Exemplo:

(quote a) => A '(cons 'a 'a) => (CONS (QUOTE A) (QUOTE A))Existe tambm uma forma de especicar expresses quase constantes, isto , expresses nas quais grande parte constante exceto alguns pontos onde se deseja avaliao. O acento grave usado no lugar do apstrofe, e as sub-expresses que se deseja avaliar so precedidas de vrgula:

`(list (+ 1 2) ,(+ 2 3) ,(+ 3 4)) => (LIST (+ 1 2) 5 7)

Exerccios1. Suponha que foram denidos:

24

(defun xxx (x) (+ 1 x)) (setf xxx 5)Qual o valor das seguintes expresses? (a) (b) (c) (d)

(xxx 2) (xxx (+ (xxx 5) 3)) (+ 4 xxx) (xxx xxx)

2. Qual o valor das expresses: (a) (b) (c) (d)

(car '((a b c d))) (cdr '((a b c d))) (car (cdr (car (cdr '((((a b) (c d)) (e f)) (g h)))))) (cons (car '(a b f)) (cons (cons 'c '(x)) nil))

25

Captulo 5 RecursoRecurso ocorre quando uma funo chama a si prpria, direta ou indiretamente. Por exemplo, considere a seguinte denio de fatorial.

(defun fatorial (n) (if (= n 0) 1 (* n (fatorial (1- n))) ) )Observe como existe uma chamada da prpria funo em seu corpo. Trata-se de uma funo recursiva. Entre as vantagens da recurso podemos citar a produo de cdigo mais compacto, e, portanto, mais fcil de manter.

5.1 O mtodo do quadradoO mtodo do quadrado uma maneira de raciocinar que pode ser til para escrever a denio de funes recursivas em LISP. A idia do mtodo

26

usar um argumento especco para determinar como o resultado da chamada recursiva deve ser trabalhado para obter o resultado a retornar. O mtodo tem este nome devido gura que desenhamos para tirar as concluses, que pode ser vista na Figura 5.1.

argumento

f

resultado de f no argumento A DESCOBRIR

cdr f

cdr do argumento

resultado de f no cdr do argumento

Figura 5.1: O mtodo do quadrado. Comeamos escolhendo um argumento especco para o clculo da funo. Este argumento colocado no canto superior esquerdo do quadrado. A partir dele, traamos uma seta para a direita, que simboliza a aplicao da funo

f

a denir. No canto superior direito colocamos o resultado de

f

aplicada

ao argumento. A seguir, descendo a partir do argumento escolhido, escrevemos o baixo simbolizando a aplicao da funo de

cdr

deste

argumento no canto inferior do quadrado. Traamos uma seta de cima para

cdr.

Na parte inferior do quan-

drado, traamos outra seta simbolizando a aplicao de

f,

levando ao valor

f

aplicada ao

cdr

do argumento. Finalmente, olhamos para o quadrado

e tentamos descobrir como que se obtm o valor no canto superior direito a partir do valor no canto inferior direito. a seta que est indicada por na gura. Vamos a um exemplo. Suponha que desejemos escrever a funo lista. Acompanhe pela Figura 5.2.

?

count

que

recebe um item e uma lista e conta o nmero de ocorrncias deste item na Em nossa denio usaremos o nome

my-count

para a funo para que, caso seja fornecida a um interpretador

LISP, a funo

count

do sistema no seja alterada.

27

a, (b a c d a f)

count

2

cdr count

?

a, (a c d a f)

2

? = somar 1 ou 0, conforme o car da lista seja ou no igual ao primeiro argumentoFigura 5.2: O mtodo do quadrado aplicado funo

count.O resultado

Escolhemos como argumentos o item de

count

a e a lista (b a c d a f).

deve ser 2, conforme ilustrado na gura. Aplicando o

gumento lista dada, temos

inalterado, ou seja, continua sendo

(a c d a f). Mantemos o primeiro argumento a. A aplicao de count na parte infe-

cdr

ao ar-

rior da gura resulta em 2 tambm. Como fazemos para obter 2 a partir de 2? Neste caso, no necessrio fazer nada, porm, se o primeiro elemento da lista fosse igual a

a,

teramos que somar uma unidade. Assim, temos a

seguinte expresso para obter o resultado a partir da chamada recursiva:

(+ (my-count item (cdr lista)) (if (equal item (car lista)) 1 0)Agora falta apenas acrescentar a condio de parada: se a lista for vazia, o contador d zero. A denio completa ca assim:

(defun my-count (item lista) (if (null lista) 0 (+ (my-count item (cdr lista)) (if (equal item (car lista)) 1 0)28

)

)

)

Fazer o exemplo da funo

my-sort,

utilizando

insertion sort.

Neste caso,

uma nova funo ter que ser criada. Isto normal em LISP. Acabamos tendo vrias funes pequenas em vez de uma grande. mais fcil de manter.

5.2 Recurso e laosA recurso pode substituir laos de repetio. Loops simples em linguagens imperativas podem ser transformados em funes LISP. Vejamos um exemplo: somar os nmeros de 1 a ser feito da seguinte forma.

n.

Numa linguagem imperativa, isto poderia

soma 0 for i 1 to n soma soma + i

Para transformar isto em recurso em LISP, as atribuies, que so impuras, se transformam em outra forma de colocar valores em variveis: chamadas de funo, onde os parmetros recebem valores. Para tal, precisamos que uma funo auxiliar cujos parmetros sejam as variveis locais prprio parmetro

n

soma

e

i,

alm do

da funo inicial.

(defun soma (n) (somaux n 0 1)) (defun somaux (n soma i) (if (> i n) soma (somaux n (+ soma i) (1+ i)) ) )29

Loops transformados em funes recursivas assim resultam numa forma de recurso especial, chamada de recurso de rabo (

tail recursion ),

mais eci-

ente do que outras formas de recurso. Recurso de rabo ocorre quando o resultado das chamadas recursivas retornado sem modicao pela funo. Existem construes LISP para loops, que sero tratadas mais adiante.

Exerccios1. Escreva a funo

last,

que recebe uma lista e retorna a ltima caixa

desta lista, ou NIL se a lista for vazia. 2. Escreva a funo

member,

que receb um item e uma lista e retorna o

suxo da lista a partir do ponto onde ocorre o item pela primeira vez nela, ou NIL caso o item no ocorra na lista. 3. Exemplo de lao para transformar em recurso: contar o nmero de positivos numa lista. 4. Combinao

n

tomados

m

a

m.

30

Captulo 6 AritmticaLISP possui um repertrio notvel de funes aritmticas. veremos algumas delas. Neste captulo

6.1 Funes bsicasComecemos pelas quatro operaes bsicas (+, argumentos. A funo

-, *, /) com 0, 1, 2, 3 ou mais

+

recebe um nmero qualquer de argumentos e retorna a soma de

todos eles. Se houver zero argumentos, retorna 0 que o elemento neutro para a adio. A funo

-

subtrai do primeiro argumento todos os outros, exceto quando

h s um argumento: da ela retorna o oposto dele. um erro cham-la com zero argumentos. A funo

*

recebe um nmero qualquer de argumentos e retorna o produto

de todos eles. Se houver zero argumentos, retorna 1 que o elemento neutro para a multiplicao. A funo

/

divide o primeiro argumento sucessivamente por cada um dos

outros, exceto quando h s um argumento: da ela retorna o inverso dele.

31

um erro cham-la com zero argumentos. D erro tambm se houver s um argumento e ele for zero, ou se houver mais de um argumento e algum dos divisores for zero. Esta funo produz razes se os argumentos so inteiros mas o resultado no inteiro.

(+) => 0 (+ 3) => 3 (+ 3 5) => 8 (+ 3 5 6) => 14 (-) => ERRO (- 3) => -3 (- 3 5) => -2 (- 3 5 6) => -8 (*) => 1 (* 3) => 3 (* 3 5) => 15 (* 3 5 6) => 90 (/) => ERRO (/ 3) => 1/3 (/ 3 5) => 3/5 (/ 3 5 6) => 1/10

Arredondamento e truncamento: donda para cima; prximos. Funes Funes

floor arredonda para baixo; ceiling arretruncate arredonda em direo ao zero; round arredonda

para o inteiro mais prximo, e escolhe o par se houver dois inteiros mais

1+

e

1-:e

incremento e decremento. mximo divisor comum (

gcd

lcm:

nimo mltiplo comum

greatest common divisor ) e m(least common multiple ). Aceitam um nmero qual-

quer de argumentos inteiros, positivos ou negativos, retornando sempre um nmero positivo ou nulo. Com zero argumentos, retornam os elementos neutros para as respectivas operaes: 0 e 1.

32

Funo

abs:

retorna o valor absoluto de seu argumento.

6.2 Funes mais sosticadasQuadrado e raiz quadrada: Funes exponenciais: Funes logartmicas:

sqr, sqrt.calcula calcula

exp, log,

ex ; expt,

calcula

xy .

e caso seja omitido a base default neperianos ou naturais.

logy x. O segundo argumento opcional, e = 2.7182817..., a base dos logaritmos

sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh. H tambm a constante pi.Funes trigonomtricas: Nmeros complexos; funo

conjugate, realpart, imagart.

Todas as fun-

es acima que faa sentido aplicar em complexos aceitam complexos e produzem as respostas corretas. Algumas delas no faz sentido aplicar em complexos: arredondar e truncar, por exemplo.

Exerccios1. Abra um livro do ensino mdio sobre fraes e use LISP para resolver expresses complicadas envolvendo fraes. Conra as respostas com as do livro. 2. Faa o mesmo para nmeros complexos.

33

Captulo 7 Denio de funesFuno vs. macro (DEFUN e DEFMACRO): macro apenas expande e no avalia nada. Argumentos: avaliados e no avaliados. Os argumentos de uma funo so sempre avaliados antes de serem passados para ela. Numa macro, no so, mas macro s para expandir. s uma convenincia de notao. O prprio DEFUN uma macro. Formas especiais tambm no avaliar seus argumentos (exemplo: condicionais). Argumentos opcionais: tm que ser sempre os ltimos, e so introduzidos atravs da chave

&optional. &restjunta todos os argumentos

Nmero varivel de argumentos: a chave

restantes numa lista e passa esta lista funo. PROGN implcito no corpo de uma funo.

Exerccios1. Escreva uma funo que aceite argumentos opcionais. 2. Escreva uma funo

mais que aceite um nmero qualquer de argumen-

tos numricos e retorne a soma de todos eles.

34

3. Escreva uma funo que aceite argumentos atravs de chaves e no de posio.

35

Captulo 8 CondicionaisNeste captulo veremos certas expresses condicionais que servem para testar condies que selecionaro uma entre vrias expresses a avaliar.

8.1 A forma especial IFA forma especial IF recebe em geral trs argumentos. Inicialmente, o primeiro argumento avaliado. Caso seja verdadeiro (isto , seu valor diferente de NIL), o segundo argumento avaliado e seu valor retornado pelo IF. Se a avaliao do primeiro argumento resultar em falso (isto , NIL), ento o terceiro argumento avaliado e seu valor retornado pelo IF. Assim, o primeiro argumento funciona como uma condio que determina quem ser escolhido como valor nal: o segundo argumento ou o terceiro argumento. O terceiro argumento de IF pode ser omitido, caso em que considerado igual a NIL. IF chamada de

forma especial

porque no necessariamente avalia todos os

seus argumentos, ao contrrio das funes. Embora qualquer valor diferente de NIL seja considerado verdadeiro, existe o valor especial T que geralmente usado quando uma funo precisa retornar um valor verdadeiro especco (por exemplo, as funes de comparao etc.).

,

36

Os smbolos NIL e T so constantes em Common LISP. Seus valores so NIL e T, respectivamente, e no podem ser modicados.

8.2 A macro CONDA macro COND implementa uma espcie de case, ou seja, uma seleo entre mltiplas alternativas. O formato geral de um COND a seguinte:

cond

{(

teste {forma }*)}* clusulas,

onde as estelas indicam repetio zero ou mais vezes. Assim, a macro COND tem um nmero qualquer de zero ou mais sendo cada uma delas uma lista de formas (expresses a avaliar). Uma clusula consiste de um

conseqentes.

teste

seguido de

A avaliao de um COND processa as clusulas da primeira ltima. Para cada clusula, o teste avaliado. Se o resultado NIL, o processamento passa para a prxima clusula. Caso contrrio, cada um dos conseqentes desta clusula availado e o valor do ltimo retornado pelo COND. Se no houver conseqentes, o valor do teste (que necessariamente diferente de NIL) retornado. Se as clusulas acabarem sem que nenhum teste seja verdadeiro, o valor retornado pelo COND NIL. comum colocar-se T como teste da ltima clusula, para evitar que isto acontea. A macro OR recebe zero ou mais argumentos e fornece uma espcie de ou lgico. Porm, ao invs de retornar somente T ou NIL, a forma OR retorna algo que pode ser mais til em determinadas situaes. Especicamente, OR avalia os argumentos da esquerda para a direita. Se

algum deles der verdadeiro, OR retorna este valor e no availa os demais. Se nenhum der verdadeiro, OR retorna NIL. A forma especial OR retorna portanto o valor do primeiro argumento que for diferente de NIL, no avaliando os demais.

37

A macro AND funciona de maneira similar: ela avalia os argumentos um a um, pra e retorna NIL ao achar o primeiro cujo valor seja NIL, e retorna o valor do ltimo se todos forem diferentes de NIL. Um caso especial o de zero argumentos, quando retorna T. Note que OR a AND foram denidos de tal forma que podem prefeitamente ser usados como funes booleanas. Alm disto existe a funo NOT, que retorna T se o argumento NIl e retorna NIL caso contrrio.

8.3 PredicadosPredicados so funes LISP que retornam um valor booleano. Alguns dos predicados mais importantes: com-ponto), lista, e nmero.

null, atom, consp, listp, numberp.

Eles

testam se seus argumentos so, respectivamente:

nulo, tomo, cons (par-

Exerccios1. Quais das seguintes funes tm comportamento igual quando aplicadas a um nico argumento:

null, not, and, or.

38

Captulo 9 Funes para listasAlgumas das funes que mencionamos abaixo vm acompanhadas de uma denio. sistema. Existem as funes rst, second, etc., at tenth: retorna o primeiro, segundo, etc. elemento da lista (h funes at para o dcimo). nth indice lista: retorna o n-simo elemento de uma lista. Os ndices comeam de zero. Nestes casos, precedemos o nome da funo com

my-

para que,

caso seja fornecida a um interpretador LISP, no altere a funo original do

(defun my-nth (indice lista) (if (= indice 0) (car lista) (my-nth (1- indice) (cdr lista)) ) )elt lista indice: mesma coisa, s que a ordem dos argumentos trocada. last lista: retorna uma lista com o ltimo elemento da lista dada. Se a lista dada for vazia, retorna NIL. Observe que esta funo no retorna o ltimo elemento, mas a ltima caixa. Porm, se for desejado o ltimo elemento,

39

basta aplicar CAR ao resultado desta funo. Foi feito desta forma para poder distingir uma lista vazia de uma lista tendo NIL como ltimo elemento.

(defun my-last (lista) (if (null lista) () (if (null (cdr lista)) lista (my-last (cdr lista)) ) ) )caar, cdar, etc. (at 6 letras a e c no meio, entre c e r): retornam a composio de at 6 aplicaes de CAR e CDR. Por exemplo:

(cdr (cdr x))).da lista.

(caddr x) equivale a (car

length lista: retorna o comprimento (nmero de elementos no nvel de topo)

(defun my-length (lista) (if (null lista) 0 (1+ (my-length (cdr lista))) ) )member item lista: se item pertence lista, retorna a parte nal da lista comeando na primeira ocorrncia de item. pertence a uma lista. Se item no pertence lista, retorna NIL. Pode ser usado como predicado para saber se um certo item

(defun my-member (item lista) (cond ((null lista) nil) ((equal item (car lista)) lista) (t (my-member item (cdr lista)))40

)

)

reverse lista: retorna uma lista com os elementos em ordem inversa relativa ordem dada.

(defun my-reverse (lista) (my-revappend lista ()) ) (defun my-revappend (lista1 lista2) (if (null lista1) lista2 (my-revappend (cdr lista1) (cons (car lista1) lista2)) ) )list &rest args: constri e retorna uma lista com os argumentos dados. Aceita um nmero qualquer de argumentos. Com zero argumentos, retorna NIL.

(defun my-list (&rest args) args )append &rest lists: retorna a concatenao de uma quantidade qualquer de listas.

(defun my-append2 (lista1 lista2) (if (null lista1) lista2 (cons (car lista1) (my-append2 (cdr lista1) lista2)) ) )subst novo velho arvore: substitui uma expresso por outra numa lista, em todos os nveis (por isto chamamos de rvore).

41

(defun my-subst (novo velho arvore) (cond ((equal velho arvore) novo) ((atom arvore) arvore) (t (cons (my-subst novo velho (car arvore)) (my-subst novo velho (cdr arvore)) ) ) ) )position item lista: retorna a primeira posio em que item aparece na lista. As posies so numeradas a partir de zero. retorna NIL. Se o item no est na lista,

(defun my-position (item lista) (cond ((null lista) nil) ((equal item (car lista)) 0) (t (let ((pos (my-position item (cdr lista)))) (and pos (1+ pos)) ) ) ) )count item lista: retorna o nmero de ocorrncias do item na lista dada. subseq lista comeco &optional nal: retorna a subseqncia de uma lista, a partir de uma posio dada, e opcionalmente terminando numa outra posio dada. As posies so numeradas a partir de zero.

(defun my-subseq (lista comeco) (if (= comeco 0) lista (my-subseq (cdr lista) (1- comeco)) ) )42

remove item lista: retorna uma nova lista obtida da lista dada pela remoo dos elementos iguais a item. A ordem relativa dos elementos restantes no alterada.

(defun my-remove (item lista) (cond ((null lista) nil) ((equal item (car lista)) (my-remove item (cdr lista))) (t (cons (car lista) (my-remove item (cdr lista)))) ) )mapcar funcao lista: retorna uma lista composta do resultado de aplicar a funo dada a cada elemento da lista dada. Nota: funes com mais de um argumento podem ser usadas, desde que sejam fornecidas tantas listas quantos argumentos a funo requer. Se as listas no forem todas do mesmo tamanho, o resultado ter o comprimento da menor.

(defun my-mapcar1 (funcao lista) (if (null lista) nil (cons (funcall funcao (car lista)) (my-mapcar1 funcao (cdr lista)) ) ) )

Exerccios1. Escreva a funo Pode usar a

append para um nmero qualquer funo append2 denida anteriormente.

de arugmentos.

43

Captulo 10 Funes para conjuntoss vezes queremos usar listas para representar conjuntos de objetos, sem nos importarmos com a ordem deles na lista. LISP oferece suporte com vrias funes que procuram imitar as operaes mais comuns entre comjuntos: unio, interseco, etc. Observe que conjuntos no tm elementos repetidos, enquanto que listas podem ter. Em cada operao, indicaremos o que ocorre quando h repeties nas listas dadas como argumentos. As denies sero novamente com

my-

precedendo o nome da funo, para

permitir testes sem comprometer a funo original denida no Common LISP. union lista1 lista2: retorna uma lista contendo todos os elementos que esto em uma das listas dadas. Se cada uma das listas dadas no contm elementos repetidos, garante-se que o resultado no contm repeties. Contudo, se as listas de entrada tiverem elementos repetidos, o resultado pode ou no conter repeties.

(defun my-union (lista1 lista2) (cond ((null lista1) lista2) ((member (car lista1) lista2) (my-union (cdr lista1) lista2)) (t (cons (car lista1) (my-union (cdr lista1) lista2)))44

)

)

intersection lista1 lista2: retorna uma lista com os elementos comuns a lista1 e lista2. Se cada uma das listas dadas no contm elementos repetidos, garantese que o resultado no contm repeties. Contudo, se as listas de entrada tiverem elementos repetidos, o resultado pode ou no conter repeties.

(defun my-intersection (lista1 lista2) (cond ((null lista1) nil) ((member (car lista1) lista2) (cons (car lista1) (my-intersection (cdr lista1) lista2))) (t (my-intersection (cdr lista1) lista2)) ) )set-dierence lista1 lista2: retorna uma lista com os elementos de lista1 que no esto em lista2.

(defun my-set-difference (lista1 lista2) (cond ((null lista1) nil) ((member (car lista1) lista2) (my-set-difference (cdr lista1) lista2)) (t (cons (car lista1) (my-set-difference (cdr lista1) lista2))) ) )subsetp lista1 lista2: retorna verdadeiro quando cada elemento de lista1 aparece na lista2.

(defun my-subsetp (lista1 lista2) (cond ((null lista1) t) ((member (car lista1) lista2) (my-subsetp (cdr lista1) lista2)) (t nil) ) )45

Todas estas funes admitem outras variaes atravs de parmetros adicionais ou maneiras diferentes de testar igualdade. Consulte a documentao ocial do Common Lisp para mais detalhes.

Exerccios1. Escreva uma funo

prod-cart

que retorne o produto cartesiano de

duas listas dadas, onde os pares ordenados so representados por listas de dois elementos. Exemplo:

> (prod-cart '(a b) '(1 2 3)) ((A 1) (A 2) (A 3) (B 1) (B 2) (B 3)A ordem dos pares no resultado no relevante.

46

Captulo 11 Pacotes (mdulos)Os objetivos do sistema de pacotes em Lisp so: oferecer modularidade e diviso do espao de nomes. Um pacote um mapeamento de nomes para smbolos. A cada momento, apenas um pacote usado para este mapeamento, o pacote corrente. A varivel global

*package* contm como valor o pacote corrente.

Cada pacote tm

seu nome. A lista de todos os pacotes existentes no sistema num certo momento pode ser obtida chamando-se a funo pr-denida

list-all-packages.

Quando um argumento para uma funo ou macro um pacote, ele geralmente dado como um smbolo cujo nome o nome do pacote. Um pacote tem smbolos internos e externos. Os smbolos externos de um pacote so a sua interface com o mundo exterior, por isso devem ter nomes bem escolhidos e anunciados a todos os usurios do sistema. pacotes. Smbolos internos so para uso interno apenas, e no devem ser acessados por outros

11.1 Acessando smbolos de outros pacotesFreqentemente, necessrio fazer referncias a smbolos de outros pacotes que no o corrente. Para acessar tais smbolos, usado o mecanismo de

47

qualicao.plo,

Isto feito usando nomes

qualicados,

que so formados por Por exem-

um nome de pacote, dois pontos (:), e o nome do smbolo.

jogador:iniciar refere-se a um smbolo de nome iniciar num pacote chamamdo jogador. Para isto, o smbolo deve ser um smbolo externo doreferido pacote.

11.1.1

Importao e exportao

Por vezes, importante referir-se a smbolos de outros pacotes sem qualicao. Para este m, existe a exportao e a importao. Um smbolo de um pacote A, para ser vsivel pelo pacote B, deve ser exportado por A e importando por B. Vejamos como fazer isto. A funo

export recebe um smbolo e o torna externo a um pacote. import,

Ele pode

ento ser importado por outros pacotes. Para importar smbolos, existe a funo que recebe uma lista de

smbolos e os importa no pacote corrente. A partir da, eles podem ser usados sem qualicao. Outra possibilidade utilizar a funo

use-package,

que

internaliza no pacote corrente todos os smbolos externos do pacote usado como argumento. A partir da, eles podem ser usados sem qualicao.

11.2 Pacotes pr-denidoscommon-lisp, um pacommon-lisp-user, o pacote default onde as denies do usurio so colocadas; keywords, pacoteAlguns pacotes j vem pr-denidfos no Common Lisp: cote que contm as funes bsicas do Common Lisp; das palavras-chave (

keywords ),

que so smbolos iniciados em dois pontos

(:), cujo valor como dado so eles mesmos e so constantes (no podem ter seu valor modicado).

48

11.3 Denindo pacotesA funo A funo

make-package

usada para criar novos pacotes. Tipicamente, ela

recebe como argumento um smbolo, cujo nome ser o nome do novo pacote.

delete-package remove do sistema o pacote especicado. A macro in-package faz com que o seu argumento passe a ser o pacote corrente.Para colocar num novo pacote um lote de denies, basta preceder as denies pelas linhas de cdigo abaixo:

(make-package 'pacote) (in-package pacote) (use-package 'common-lisp)A seguir, pode-se colocar uma chamada de que se deseja exportar.

export para exportar os smbolos

Exerccios1. Crie um novo pacote, dena nele uma funo e exporte esta funo. Depois v para o pacote a notao

common-lisp-user e chame esta funo usando pacote:funcao.

49

Captulo 12 Arrays e Loops12.1 Arrays12.1.1 Criando arrays

A funo

make-array

retorna uma nova array. Seu parmetro uma lista

de dimenses, por exemplo, terceiro vai de 0 a 6.

(make-array '(4 3 7)) retorna uma array tri-

dimensional onde o primeiro ndice vai de 0 a 3, o segundo vai de 0 a 2, e o

12.1.2

Acessando arrays

A funo

aref

recebe uma array e ndices e retorna o elemento da array na

posio especicada pelos ndices. Por exemplo, se a varivel array criada no pargrafo anterior, a chamada elemento indexado por 2, 1 e 6 (equivalente a C ou

mat[2,1,6] setf

mat contiver a (aref mat 2 1 6) retorna o algo como mat[2][1][6] em

em Pascal).

A macro

pode ser usada com

aref

para modicar o elemento numa

dada posio de uma array.

50

12.2 LoopsH vrias formas de fazer contrues iterativas em Lisp, mas aqui vamos apenas dar dois exemplos: as macros Lisp. A forma geral :

dolist e dotimes.

O leitor interessado

poder encontrar outras construes mais complexas no manual de Common

dolist executa iterao sobre os elementos de uma lista.

O formato

dolist (var listform [resultform ]) {declaration } {tag | statement }Primeiramente, a forma varivel

listform

avaliada e deve produzir uma lista. Em Ento a forma

seguida o corpo executado uma vez para cada elemento da lista, com a

var

tendo como valor este elemento.

avaliada e seu valor retornado pela macro A forma

dolist.

resultform

dotimes

executa iterao sobre uma seqncia de inteiros. O for-

mato geral :

dotimes (var countform [resultform ]) {declaration } {tag | statement }Primeiramente, a forma

countform avaliada e deve produzir um inteiro. var

Em

seguida o corpo executado uma vez para cada inteiro de zero ao valor deste inteiro menos um, com a varivel forma

resultform

tendo como valor este inteiro. Ento a

avaliada e seu valor retornado pela macro

dotimes.

Em ambos os casos, se

resultform

omitida, o resultado NIL.

Exerccios1. Escreva uma expresso que imprime os elementos de uma lista usando

dolist.2. Escreva uma expresso que some os elementos de 0 a

n usando dotimes.

51

Bibliograa[1] John L. McCarthy. Recursive functions of symbolic expressions and their computation by machine, part i. 195, 1960. [2] Edward H. Shortlie.

Communications of the ACM, 3(4):184

Computer-Based Medical Consultation: MYCIN.

Elsevier North Holland, 1976. [3] Guy L. Steele.

Common Lisp the Language. Digital Press, second edition,

1990. ISBN 1-55558-041-6. [4] Joseph Weizenbaum. ELIZA - a computer program for the study of natu-

of the ACM, 9(1):3645, January 1966.

ral language communication between man and machine.

Communications

52