Escolar Documentos
Profissional Documentos
Cultura Documentos
Lisp
João Meidanis
c Copyright 2013 J. Meidanis
Conteúdo
1 Introdução 4
1.1 Calculando derivadas simbólicas . . . . . . . . . . . . . . . . . 4
1.2 O psiquiatra . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3 MYCIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.4 Interpretador . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2 Elementos da linguagem 10
2.1 Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2 Números . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3 Símbolos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.4 Pares-com-ponto . . . . . . . . . . . . . . . . . . . . . . . . . 12
3 Estrutura da linguagem 17
1
3.1 Denindo funções . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.2 Condicionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4 Símbolos 22
4.1 Avaliação e valores de um símbolo . . . . . . . . . . . . . . . . 22
5 Recursão 26
5.1 O método do quadradão . . . . . . . . . . . . . . . . . . . . . 26
6 Aritmética 31
6.1 Funções básicas . . . . . . . . . . . . . . . . . . . . . . . . . . 31
7 Denição de funções 34
8 Condicionais 36
8.1 A forma especial IF . . . . . . . . . . . . . . . . . . . . . . . . 36
8.3 Predicados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2
10 Funções para conjuntos 44
11 Pacotes (módulos) 47
11.1 Acessando símbolos de outros pacotes . . . . . . . . . . . . . . 47
12 Arrays e Loops 50
12.1 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
12.2 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3
Capítulo 1
Introdução
LISP vem de list processing. John McCarthy criou LISP em 1960 [1].
LISP é uma linguagem tão antiga que na época em que foi criada os com-
putadores SÓ USAVAM LETRAS MAIÚSCULAS. Quando vieram as letras
minúsculas, foi adotada a convenção de que em LISP uma letra minúscula
ou maiúscula é a mesma coisa. Portanto, as palavras 'SEN', 'sen' e 'SeN' em
LISP são todas equivalentes.
4
Exemplo:
d 2
(x + 3x) = 2x + 3,
dx
d cos x
(log sin x) = .
dx sin x
Para denotar as funções neste programa é usada uma notação pré-xa, típica
2
de LISP. A função x + 3x, por exemplo, é denotada por:
(+ (* X X) (* 3 X)).
Se for denida uma função chamada DERIV para calcular a derivada, pode-se
pedir:
(+ (* 2 x) 3)
ou seja, 2x + 3.
1.2 O psiquiatra
ELIZA, que pretendia simular um psiquatra, foi talvez o primeiro programa
de computador a passar o Teste de Turing. Foi escrito por Joseph Weizen-
baum em 1966 [4].
5
Men are all alike.
IN WHAT WAY?
1.3 MYCIN
MYCIN, um sistema pioneiro para diagnósticos médicos, foi um dos precur-
sores dos sistemas especialistas [2].
As regras são na verdade escritas como expressões LISP. O valor 0.7 é uma
estimativa de que a conclusão seja correta dadas as evidências. Se as evi-
dências são também incertas, as suas estimativas serão combinadas com as
desta regra para chegar à estimativa de correção da conclusão.
6
1.4 Interpretador
A maneira padrão de interação com uma implementação de Common Lisp
é através de um laço ler-avaliar-imprimir ( read-eval-print loop ): o sistema
repetidamente lê uma expressão a partir de uma fonte de entrada de dados
(geralmente o teclado ou um arquivo), avalia a expressão, e imprime o(s)
valor(es) em um destino de saída (geralmente a tela ou um arquivo).
Quando uma lista é avaliada (exceto nos casos de macros e formas especiais),
supõe-se que seja uma chamada de função. O primeiro elemento da lista é
tomado como sendo o nome da função. Todos os outros elementos da lista
são tratados como expressões a serem avaliadas também; um valor é obtido
de cada uma, e estes valores se tornam os argumentos da função. A função
é então aplicada aos argumentos, resultando em um ou mais valores (exceto
nos casos de retornos não locais). Se e quando a função retornar, os valores
retornados tornam-se os valores da lista avaliada.
7
Em geral, as modicações serão poucas ou menhuma, especialemnte se você
usar construções portáteis. Só serão aceitos projetos que rodem em CMUCL.
entrar: lisp
sair: (quit)
usar com arquivo: escreva um arquivo de texto simples com as
expressões a avaliar, dê a ele extensão .lsp, e chame lisp <
arquivo.lsp
usar sem arquivos: simplesmente tecle as expressões (ou formas)
seguidas de ENTER
repetir última expressão: *
repetir penúltima expressão: **
repetir antepenúltima expressão: ***
Uma grande vantagem de usar o editor Emacs é que ele balanceia os parên-
teses para você. E cuida também da indentação.
8
Compilação vs. interpretação: além de interpretador, o Common Lisp
prevê que seja compiladas funções ou arquivos LISP, para rodarem mais
rápido. Para compilar uma função deriv, por exemplo, use:
(compile 'deriv).
(compile-file "deriv.lsp").
Exercícios
9
Capítulo 2
Elementos da linguagem
2.1 Tipos
Tipos em LISP: só para dados, não para variáveis. Lista completa de tipos:
array, atom, base-character, bignum, bit, bit-vector, character, compiled-
function, complex, cons, double-oat, extended-character, xnum, oat, func-
tion, hash-table, integer, keyword, list, long-oat, nil, null, number, package,
pathname, random-state, ratio, rational, readtable, sequence, short-oat,
signed-byte, simple-array, simple-bit-vector, simple-string, simple-vector, single-
oat, standard-char, stream, string, symbol, t, unsigned-byte, vector.
Além destes, podem ser criados outros pelo usuário (classes, etc.).
2.2 Números
Números: inteiros, razões, ponto utuante, complexos.
10
Figura 2.1: Hierarquia parcial de tipos em Lisp.
2.3 Símbolos
Símbolos: serão tratados no Capítulo 4. Por enquanto, vamos considerá-
los como seqüências de caracteres que podem incluir letras, números e sinais
especiais, exceto brancos e parênteses, e que não possam ser confundidos com
números. Além disso, não devem conter apenas pontos.
FROBBOZ
frobboz
fRObBoz
unwind-protect
11
+&
1+
pascal_style
b^2-4*a*c
file.rel.43
/usr/games/zork
+1
..
2.4 Pares-com-ponto
Pares-com-ponto, ou conses: são estruturas, ou registros, com dois compo-
nentes: car e cdr. Dentre os conses, destacamos as listas.
Listas: uma lista é denida como sendo ou bem a lista vazia ou bem um cons
cujo cdr é uma lista. O símbolo NIL é usado para denotar a lista vazia. A
expressão () é sinônima de NIL.
Um cons cujo segundo elemento não é uma lista é denotado de forma seme-
lhante, exceto há um ponto . (cercado de espaço em branco) precedendo o
último cdr. Exemplo: (a . 4) é um cons cujo car é um símbolo e cujo cdr
é um número. Daí o nome par-com-ponto.
12
A B
A 1 "ca"
X 10.0
13
A NIL
NIL
A E
A B
A função CONS recebe dois argumentos e retorna uma nova caixa contendo
estes argumentos como componentes, na ordem dada. Não há sinônimos para
CONS. Exemplos:
14
2.7 Coleta de lixo
A liguagem LISP foi a primeira a adotar um sistema de gerenciamento de me-
mória conhecido como coleção de lixo ( garbage collection ). Neste sistema, o
programador não precisa se preocupar em alocar ou desalocar memória expli-
citamente. Ao invés disso, o próprio interpretador da linguagem se encarrega
de alocar e desalocar memória quando necessário. A alocação de memória
ocorre sempre que CONS é chamada, direta ou indiretamente. Quanto à de-
salocação, ela ocorre quando é necessário alocar mais memória mas acabou
a memória do sistema. Neste momento o interpretador sai coletando lixo,
que são caixas que não estão sendo mais apontadas por nenhuma estrutura
do sistema, e que podem portanto ser liberadas. Por exemplo, na avaliação
da expressão:
Hoje em dia há várias linguagens que fazem coleta de lixo, entre elas Perl,
Python e Java.
Exercícios
15
6. Calcule o CAR e o CDR das expressões dos dois últimos exercícios.
16
Capítulo 3
Estrutura da linguagem
17
Antes, porém, vamos relembrar como efetuar operações aritméticas em LISP.
As quatro operações básicas da aritmética são implementadas pelas funções
pré-denidas indicadas por +, -, *, / e a notação é prexa.
Note que a função * admite mais de dois argumentos. Neste exemplo, usamos
três argumentos. Ela simplesmente multiplica todos e retorna o resultado.
A função + também aceita um número variável de argumentos.
3.2 Condicionais
Para prosseguir no nosso estudo de LISP, precisamos conhecer os condicio-
nais, que permitem seleção de uxos alternativos de código. Em LISP, os
mais usados são IF e COND.
18
(defun maior (x y) (if (> x y) x y)
Note o uso de uma nova função pré-denida: >. Podemos também denir
uma função para retornar o maior entre três números:
(defun maior3 (x y z)
(if (> x y)
(if (> x z) x z)
(if (> y z) y z)
)
)
(defun maior (x y)
(cond
((> x y) x)
(t y)
)
)
19
Observe o uso de T para garantir a captura do controle caso o primeiro teste
falhe.
(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 função: and, uma função lógica para a conjunção.
Existe também or. Tivemos que usar desigualdades não estritas para garantir
que algum dos números seja o vencedor.
(defun raiz (a b c)
(let ((disc (discr a b c)))
(/ (+) (- b) (sqrt disc)) (* 2 a))
)
20
Mais de uma variável local pode ser denida no mesmo bloco LET. Existe
também uma variante do LET, chamada LET∗, que permite que cada variável
dependa da anterior. A função a seguir utiliza este recurso e também a
função pré-denida LIST para a formação de uma lista com as duas raízes
da equação:
(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.
Exercícios
21
Capítulo 4
Símbolos
22
hora de avaliar, uma lista é sempre vista como a chamada de uma função. O
primeiro elemento da lista é o nome da função e os elementos restantes são
os argumentos. Para avaliar uma lista, LISP procura o valor como função do
primeiro elemento, depois avalia os argumentos, e nalmente aplica a função
nos valores dos argumentos.
(+ 1 2 3)
LISP busca o valor como função do símbolo +, que resulta numa função pré-
denida que soma números. Depois, LISP avalia os argumentos, que no caso
são números e portanto correspondem a seus próprios valores. Finalmente,
LISP aplica a função pré-denida nos valores 1, 2 e 3, resultando em 6.
(setf x 8)
Observe que esta é uma forma impura de modicar o valor como dado de
um símbolo, pois resulta de um efeito colateral, e naõ guarda o valor anterior
para se desfazer a ação, caso necessário. Existem outras formas de modicar
o valor como dado de um símbolo que são mais puras, ou seja, tem efeito
temporário, e o símbolo volta ao valor anterior ao nal de um certo processo.
São elas: o bloco LET e a passagem de parâmetros a uma função. Note
23
que tanto o LET como a chamada de uma função fazem uma atribuição de
valores a certos símbolos, e esta atribuição é desfeita após o m do processo
correspondente (m do bloco LET no primeiro caso; m da execução da
função, no segundo caso).
QUOTE é uma forma especial que retorna seu argumento sem avaliação.
É utilizada para introduzir expressões constantes. É tão usada que inventa-
ram uma abreviatura: apóstrofe precedendo uma expressão signica QUOTE
aplicada a esta expressão. Exemplo:
(quote a) => A
'(cons 'a 'a) => (CONS (QUOTE A) (QUOTE A))
Exercícios
24
(defun xxx (x)
(+ 1 x))
(setf xxx 5)
(a) (xxx 2)
(b) (xxx (+ (xxx 5) 3))
(c) (+ 4 xxx)
(d) (xxx xxx)
2. Qual o valor das expressões:
25
Capítulo 5
Recursão
Observe como existe uma chamada da própria função em seu corpo. Trata-se
de uma função recursiva.
26
usar um argumento especíco para determinar como o resultado da chamada
recursiva deve ser trabalhado para obter o resultado a retornar. O método
tem este nome devido à gura que desenhamos para tirar as conclusões, que
pode ser vista na Figura 5.1.
f resultado de f
argumento no argumento
cdr A DESCOBRIR
f resultado de f
cdr do argumento no cdr do argumento
27
count
a, (b a c d a f) 2
cdr ?
count
a, (a c d a f) 2
28
)
)
)
soma ← 0
for i ← 1 to n
soma ← soma + i
29
Loops transformados em funções recursivas assim resultam numa forma de
recursão especial, chamada de recursão de rabo ( tail recursion ), mais eci-
ente do que outras formas de recursão. Recursão de rabo ocorre quando o
resultado das chamadas recursivas é retornado sem modicação pela função.
Existem construções LISP para loops, que serão tratadas mais adiante.
Exercícios
1. Escreva a função last, que recebe uma lista e retorna a última caixa
desta lista, ou NIL se a lista for vazia.
4. Combinação n tomados m a m.
30
Capítulo 6
Aritmética
31
É um erro chamá-la com zero argumentos. Dá erro também se houver só um
argumento e ele for zero, ou se houver mais de um argumento e algum dos
divisores for zero. Esta função produz razões se os argumentos são inteiros
mas o resultado não é inteiro.
(+) => 0
(+ 3) => 3
(+ 3 5) => 8
(+ 3 5 6) => 14
(*) => 1
(* 3) => 3
(* 3 5) => 15
(* 3 5 6) => 90
Funções gcd e lcm: máximo divisor comum (greatest common divisor ) e mí-
nimo múltiplo comum (least common multiple ). Aceitam um número qual-
quer de argumentos inteiros, positivos ou negativos, retornando sempre um
número positivo ou nulo. Com zero argumentos, retornam os elementos neu-
tros para as respectivas operações: 0 e 1.
32
Função abs: retorna o valor absoluto de seu argumento.
Exercícios
1. Abra um livro do ensino médio sobre frações e use LISP para resolver
expressões complicadas envolvendo frações. Conra as respostas com
as do livro.
33
Capítulo 7
Denição de funções
Exercícios
34
3. Escreva uma função que aceite argumentos através de chaves e não de
posição.
35
Capítulo 8
Condicionais
Neste capítulo veremos certas expressões condicionais que servem para testar
condições que selecionarão uma entre várias expressões a avaliar.
36
Os símbolos NIL e T são constantes em Common LISP. Seus valores são NIL
e T, respectivamente, e não podem ser modicados.
onde as estelas indicam repetição zero ou mais vezes. Assim, a macro COND
tem um número qualquer de cláusulas, sendo cada uma delas uma lista de
formas (expressões a avaliar). Uma cláusula consiste de um teste seguido de
zero ou mais conseqüentes.
A avaliação de um COND processa as cláusulas da primeira à última. Para
cada cláusula, o teste é avaliado. Se o resultado é NIL, o processamento
passa para a próxima cláusula. Caso contrário, cada um dos conseqüentes
desta cláusula é availado e o valor do último é retornado pelo COND. Se
não houver conseqüentes, o valor do teste (que é necessariamente diferente
de NIL) é retornado.
37
A macro AND funciona de maneira similar: ela avalia os argumentos um a
um, pára 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 funções booleanas. Além disto existe a função NOT, que
retorna T se o argumento é NIl e retorna NIL caso contrário.
8.3 Predicados
Predicados são funções LISP que retornam um valor booleano. Alguns dos
predicados mais importantes: null, atom, consp, listp, numberp. Eles
testam se seus argumentos são, respectivamente: nulo, átomo, cons (par-
com-ponto), lista, e número.
Exercícios
38
Capítulo 9
Existem as funções rst, second, etc., até tenth: retorna o primeiro, segundo,
etc. elemento da lista (há funções até para o décimo).
nth indice lista: retorna o n-ésimo elemento de uma lista. Os índices começam
de zero.
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 função não retorna o último
elemento, mas a última caixa. Porém, se for desejado o último elemento,
39
basta aplicar CAR ao resultado desta função. Foi feito desta forma para po-
der distingüir uma lista vazia de uma lista tendo NIL como último elemento.
caar, cdar, etc. (até 6 letras a e c no meio, entre c e r): retornam a composição
de até 6 aplicações de CAR e CDR. Por exemplo: (caddr x) equivale a (car
(cdr (cdr x))).
member item lista: se item pertence à lista, retorna a parte nal da lista
começando na primeira ocorrência de item. Se item não pertence à lista,
retorna NIL. Pode ser usado como predicado para saber se um certo item
pertence a uma lista.
40
)
)
reverse lista: retorna uma lista com os elementos em ordem inversa relativa
à ordem dada.
list &rest args: constrói e retorna uma lista com os argumentos dados. Aceita
um número qualquer de argumentos. Com zero argumentos, retorna NIL.
subst novo velho arvore: substitui uma expressão por outra numa lista, em
todos os níveis (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 posição em que item aparece na lista.
As posições são numeradas a partir de zero. Se o item não está na lista,
retorna NIL.
42
remove item lista: retorna uma nova lista obtida da lista dada pela remoção
dos elementos iguais a item. A ordem relativa dos elementos restantes não é
alterada.
Exercícios
43
Capítulo 10
Às vezes queremos usar listas para representar conjuntos de objetos, sem nos
importarmos com a ordem deles na lista. LISP oferece suporte com várias
funções que procuram imitar as operações mais comuns entre comjuntos:
união, intersecção, etc.
Observe que conjuntos não têm elementos repetidos, enquanto que listas po-
dem ter. Em cada operação, indicaremos o que ocorre quando há repetições
nas listas dadas como argumentos.
union lista1 lista2: retorna uma lista contendo todos os elementos que estão
em uma das listas dadas. Se cada uma das listas dadas não contém elementos
repetidos, garante-se que o resultado não contém repetições. Contudo, se as
listas de entrada tiverem elementos repetidos, o resultado pode ou não conter
repetições.
44
)
)
intersection lista1 lista2: retorna uma lista com os elementos comuns a lista1 e
lista2. Se cada uma das listas dadas não contém elementos repetidos, garante-
se que o resultado não contém repetições. Contudo, se as listas de entrada
tiverem elementos repetidos, o resultado pode ou não conter repetições.
set-dierence lista1 lista2: retorna uma lista com os elementos de lista1 que
não estão em lista2.
subsetp lista1 lista2: retorna verdadeiro quando cada elemento de lista1 apa-
rece na lista2.
45
Todas estas funções admitem outras variações através de parâmetros adici-
onais ou maneiras diferentes de testar igualdade. Consulte a documentação
ocial do Common Lisp para mais detalhes.
Exercícios
46
Capítulo 11
Pacotes (módulos)
47
qualicação. Isto é feito usando nomes qualicados, que são formados por
um nome de pacote, dois pontos (:), e o nome do símbolo. Por exem-
plo,jogador:iniciar refere-se a um símbolo de nome iniciar num pacote
chamamdo jogador. Para isto, o símbolo deve ser um símbolo externo do
referido pacote.
Para importar símbolos, existe a função import, que recebe uma lista de
símbolos e os importa no pacote corrente. A partir daí, eles podem ser usados
sem qualicação. Outra possibilidade é utilizar a função use-package, que
internaliza no pacote corrente todos os símbolos externos do pacote usado
como argumento. A partir daí, eles podem ser usados sem qualicação.
48
11.3 Denindo pacotes
A função make-package é usada para criar novos pacotes. Tipicamente, ela
recebe como argumento um símbolo, cujo nome será o nome do novo pacote.
A funçãodelete-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 denições, basta preceder as de-
nições pelas linhas de código abaixo:
(make-package 'pacote)
(in-package pacote)
(use-package 'common-lisp)
Exercícios
1. Crie um novo pacote, dena nele uma função e exporte esta função.
Depois vá para o pacotecommon-lisp-user e chame esta função usando
a notação pacote:funcao.
49
Capítulo 12
Arrays e Loops
12.1 Arrays
12.1.1 Criando arrays
A função make-array retorna uma nova array. Seu parâmetro é uma lista
de dimensões, por exemplo, (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
terceiro vai de 0 a 6.
A macro setf pode ser usada com aref para modicar o elemento numa
dada posição de uma array.
50
12.2 Loops
Há várias formas de fazer contruções iterativas em Lisp, mas aqui vamos
apenas dar dois exemplos: as macros dolist e dotimes. O leitor interessado
poderá encontrar outras construções mais complexas no manual de Common
Lisp.
Exercícios
51
Bibliograa
[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-
ral language communication between man and machine. Communications
of the ACM, 9(1):3645, January 1966.
52