Você está na página 1de 165

Introduo Programao com AutoLisp

Antnio Menezes Leito


Fevereiro 2007
Contedo
1 Programao 4
1.1 Linguagens de Programao . . . . . . . . . . . . . . . . . . . . . 6
1.2 Lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.3 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2 Sintaxe, Semntica e Pragmtica 9
2.1 Sintaxe e Semntica do Lisp . . . . . . . . . . . . . . . . . . . . . 9
2.2 O Avaliador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3 Elementos da Linguagem 11
3.1 Elementos primitivos . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.1.1 Nmeros . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.2 Avaliao de Combinaes . . . . . . . . . . . . . . . . . . . . . . 13
3.3 Operadores de Strings . . . . . . . . . . . . . . . . . . . . . . . . 14
3.4 Denio de Funes . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.5 Smbolos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.6 Avaliao de Smbolos . . . . . . . . . . . . . . . . . . . . . . . . 18
3.7 Funes de Mltiplos Parmetros . . . . . . . . . . . . . . . . . . 19
3.8 Encadeamento de Funes . . . . . . . . . . . . . . . . . . . . . . 20
3.9 Funes Pr-Denidas . . . . . . . . . . . . . . . . . . . . . . . . 21
3.10 Aritmtica de Inteiros em Auto Lisp . . . . . . . . . . . . . . . . 23
3.11 Aritmtica de Reais em Auto Lisp . . . . . . . . . . . . . . . . . 25
3.12 Smbolos e Avaliao . . . . . . . . . . . . . . . . . . . . . . . . . 26
4 Combinao de Dados 31
4.1 Coordenadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.2 Pares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.3 Operaes com Coordenadas . . . . . . . . . . . . . . . . . . . . 33
4.4 Abstraco de Dados . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.5 Coordenadas Tri-Dimensionais . . . . . . . . . . . . . . . . . . . 37
4.6 Coordenadas Bi- e Tri-Dimensionais . . . . . . . . . . . . . . . . 40
4.7 A Notao de Lista . . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.8 tomos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.9 Tipos Abstractos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
4.10 Coordenadas em AutoCad . . . . . . . . . . . . . . . . . . . . . . 46
4.11 Coordenadas Polares . . . . . . . . . . . . . . . . . . . . . . . . . 47
4.12 A funo command . . . . . . . . . . . . . . . . . . . . . . . . . . 50
4.13 Variantes de Comandos . . . . . . . . . . . . . . . . . . . . . . . 56
4.14 ngulos em Comandos . . . . . . . . . . . . . . . . . . . . . . . . 57
4.15 Efeitos Secundrios . . . . . . . . . . . . . . . . . . . . . . . . . . 58
4.16 A Ordem Drica . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
4.17 Parameterizao de Figuras Geomtricas . . . . . . . . . . . . . 62
4.18 Documentao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4.19 Depurao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
4.19.1 Erros Sintticos . . . . . . . . . . . . . . . . . . . . . . . . 70
1
4.19.2 Erros Semnticos . . . . . . . . . . . . . . . . . . . . . . . 71
5 Modelao Tridimensional 74
5.1 Slidos Tridimensionais Pr-Denidos . . . . . . . . . . . . . . . 74
5.2 Modelao de Colunas Dricas . . . . . . . . . . . . . . . . . . . 78
6 Expresses Condicionais 81
6.1 Expresses Lgicas . . . . . . . . . . . . . . . . . . . . . . . . . . 81
6.2 Valores Lgicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
6.3 Predicados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
6.4 Predicados Aritmticos . . . . . . . . . . . . . . . . . . . . . . . . 82
6.5 Operadores Lgicos . . . . . . . . . . . . . . . . . . . . . . . . . . 82
6.6 Predicados com nmero varivel de argumentos . . . . . . . . . 83
6.7 Predicados sobre Cadeias de Caracteres . . . . . . . . . . . . . . 84
6.8 Predicados sobre Smbolos . . . . . . . . . . . . . . . . . . . . . . 84
6.9 Predicados sobre Listas . . . . . . . . . . . . . . . . . . . . . . . . 84
6.10 Reconhecedores . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
6.11 Reconhecedores Universais . . . . . . . . . . . . . . . . . . . . . 85
6.12 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
7 Estruturas de Controle 88
7.1 Sequenciao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
7.2 Invocao de Funes . . . . . . . . . . . . . . . . . . . . . . . . . 89
7.3 Variveis Locais . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
7.4 Atribuio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
7.5 Variveis Globais . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
7.6 Variveis Indenidas . . . . . . . . . . . . . . . . . . . . . . . . . 94
7.7 Propores de Vitrvio . . . . . . . . . . . . . . . . . . . . . . . . 95
7.8 Seleco . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
7.9 Seleco MltiplaA Forma cond . . . . . . . . . . . . . . . . . 99
7.10 Seleco nas Propores de Vitrvio . . . . . . . . . . . . . . . . 101
7.11 Operaes com Coordenadas . . . . . . . . . . . . . . . . . . . . 105
7.12 Coordenadas Cilndricas . . . . . . . . . . . . . . . . . . . . . . . 110
7.13 Coordenadas Esfricas . . . . . . . . . . . . . . . . . . . . . . . . 111
7.14 Recurso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
7.15 Depurao de Programas Recursivos . . . . . . . . . . . . . . . . 119
7.15.1 Trace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
7.16 Templos Dricos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
7.17 A Ordem Jnica . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
7.18 Recurso na Natureza . . . . . . . . . . . . . . . . . . . . . . . . 138
8 Atribuio 145
8.1 Aleatoriedade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
8.2 Nmeros Aleatrios . . . . . . . . . . . . . . . . . . . . . . . . . 146
8.3 Estado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
8.4 Estado Local e Estado Global . . . . . . . . . . . . . . . . . . . . 150
8.5 Escolhas Aleatrias . . . . . . . . . . . . . . . . . . . . . . . . . . 150
2
8.5.1 Nmeros Aleatrios Fraccionrios . . . . . . . . . . . . . 153
8.5.2 Nmeros Aleatrios num Intervalo . . . . . . . . . . . . 153
8.6 Planeamento Urbano . . . . . . . . . . . . . . . . . . . . . . . . . 156
3
1 Programao
A transmisso de conhecimento um dos problemas que desde cedo preo-
cupou a humanidade. Sendo o homem capaz de acumular conhecimento ao
longo de toda a sua vida, com desnimo que enfrenta a ideia de que, com a
morte, todo esse conhecimento se perca.
Para o evitar, a humanidade inventou toda uma srie de mecanismos de
transmisso de conhecimento. O primeiro, a transmisso oral, consiste na
transmisso do conhecimento de uma pessoa para um grupo reduzido de
outras pessoas, de certa forma transferindo o problema da perda de conhe-
cimento para a gerao seguinte. O segundo, a transmisso escrita, consiste
em registar em documentos o conhecimento que se pretende transmitir. Esta
forma tem a grande vantagem de, por um lado, poder chegar a muitas mais
pessoas e, por outro, de reduzir signicativamente o risco de se perder o co-
nhecimento por problemas de transmisso. De facto, a palavra escrita per-
mite preservar por muito tempo e sem qualquer tipo de adulterao o conhe-
cimento que o autor pretendeu transmitir.
graas palavra escrita que hoje conseguimos compreender e acumular
um vastssimo conjunto de conhecimentos, muitos deles registados h milha-
res de anos atrs.
Infelizmente, nem sempre a palavra escrita conseguiu transmitir com rigor
aquilo que o autor pretendia. A lngua natural tem inmeras ambiguidades
e evolui substancialmente com o tempo, o que leva a que a interpretao dos
textos seja sempre uma tarefa subjectiva. Quer quando escrevemos um texto,
quer quando o lemos e o interpretamos, existem omisses, imprecises, in-
correces e ambiguidades que podem tornar a transmisso de conhecimento
falvel. Se o conhecimento que se est a transmitir for simples, o receptor da
informao, em geral, consegue ter a imaginao e a capacidade sucientes
para conseguir ultrapassar os obstculos mas, no caso da transmisso de co-
nhecimentos mais complexos j isso poder ser muito mais difcil.
Infelizmente, quando se exige rigor na transmisso de conhecimento, fazer
depender a compreenso desse conhecimento da capacidade de interpretao
de quem o recebe pode ter consequncias desastrosas e, de facto, a histria
da humanidade est repleta de acontecimentos catastrcos cuja causa , to
somente, uma insuciente ou errnea transmisso de conhecimento.
Para evitar estes problemas, inventaram-se linguagens mais rigorosas. A
matemtica, em particular, tem-se obssessivamente preocupado ao longo dos
ltimos milnios com a construo de uma linguagem onde o rigor seja abso-
luto. Isto permite que a transmisso do conhecimento matemtico seja muito
mais rigorosa que nas outras reas, reduzindo ao mnimo essencial a capaci-
dade de imaginao necessria de quem est a absorver esse conhecimento.
Para melhor percebermos do que estamos a falar, consideremos, a ttulo
de exemplo, a transmisso do conhecimento relativo funo factorial. Se
assumirmos, como ponto de partida, que a pessoa a quemqueremos transmitir
esse conhecimento j sabe de antemo o que so os nmeros, as variveis e as
operaes aritmticas, podemos denir matematicamente a funo factorial
4
nos seguintes termos:
n! = 1 2 3 (n 1) n
Ser a denio anterior sucientemente rigorosa? Ser possvel interpret-
la sem necessitar de imaginar a inteno do autor? Aparentemente, sim mas,
na verdade, h um detalhe da denio que exige imaginao: as reticncias.
Aquelas reticncias indicamao leitor que ele ter de imaginar o que deveria es-
tar no lugar delas e, embora a maioria dos leitores ir imaginar correctamente
que o autor pretendia a multiplicao dos sucessores dos nmeros anteriores,
leitores haver cuja imaginao delirante poder tentar substituir aquelas reti-
cncias por outra coisa qualquer.
Mesmo que excluamos do nosso pblico-alvo as pessoas de imaginao
delirante, h ainda outros problemas com a denio anterior. Pensemos, por
exemplo, no factorial de 2. Qual ser o seu valor? Se substituirmos na frmula,
para n = 2 obtemos:
2! = 1 2 3 1 2
Neste caso, no s as reticncias deixam de fazer sentido como toda a frmula
deixa de fazer sentido, o que mostra que, na verdade, a imaginao necessria
para a interpretao da frmula original no se restringia apenas s reticn-
cias mas sim a toda a frmula: o nmero de termos a considerar depende do
nmero do qual queremos saber o factorial.
Admitindo que o nosso leitor teria tido a imaginao suciente para des-
cobrir esse detalhe, ele conseguiria tranquilamente calcular que 2! = 12 = 2.
Ainda assim, casos haver que o deixaro signicativamente menos tranquilo.
Por exemplo, qual o factorial de zero? A resposta no parece bvia. E quanto
ao factorial de 1? Novamente, no est claro. E quanto ao factorial de 4.5?
Mais uma vez, a frmula nada diz e a nossa imaginao tambm no consegue
adivinhar.
Ser possvel encontrar uma forma de transmitir o conhecimento da funo
factorial que minimize as imprecises, lacunas e ambiguidades? Ser possvel
reduzir ao mnimo razovel a imaginao necessria para compreender esse
conhecimento? Experimentemos a seguinte variante da denio da funo
factorial:
n! =

1, se n = 0
n (n 1)!, se n N.
Teremos agora atingido o rigor suciente que dispensa imaginao por
parte do leitor? A resposta estar na anlise dos casos que causaram proble-
mas denio anterior. Em primeiro lugar, no existem reticncias, o que
positivo. Em segundo lugar, para o factorial de 2 temos, pela denio:
2! = 2 1! = 2 (1 0!) = 2 (1 1) = 2 1 = 2
ou seja, no h qualquer ambiguidade. Finalmente, vemos que no faz sentido
determinar o factorial de 1 ou de 4.5 pois a denio apresentada apenas se
aplica aos membros de N
0
.
5
Este exemplo mostra que, mesmo na matemtica, h diferentes graus de
rigor nas diferentes formas como se expe o conhecimento. Algumas dessas
formas exigem um pouco mais de imaginao e outras um pouco menos mas,
em geral, qualquer delas tem sido suciente para que a humanidade tenha
conseguido preservar o conhecimento adquirido ao longo da sua histria.
1
Acontece que, actualmente, a humanidade conta com um parceiro que tem
dado uma contribuio gigantesca para o seu progresso: o computador. Esta
mquina tem a extraordinria capacidade de poder ser instruda de forma a
saber executar um conjunto complexo de tarefas. A actividade da programao
consiste, precisamente, da transmisso, a um computador, do conhecimento
necessrio para resolver um determinado problema. Esse conhecimento de-
nominado um programa. Por serem programveis, os computadores tm sido
usados para os mais variados ns e, sobretudo nas ltimas dcadas, tm trans-
formado radicalmente a forma como trabalhamos. Infelizmente, a extraordi-
nria capacidade de aprendizagem dos computadores vem acompanhada
duma igualmente extraordinria incapacidade de imaginao. O computador
no imagina, apenas interpreta rigorosamente o conhecimento que lhe trans-
mitimos sob a forma de um programa.
Uma vez que no tem imaginao, o computador depende criticamente da
forma como lhe apresentamos o conhecimento que queremos transmitir: esse
conhecimento tem de estar descrito numa linguagem tal que no possa haver
margem para qualquer ambiguidade, lacuna ou impreciso. Uma linguagem
com estas caractersticas denomina-se, genericamente, de linguagem de progra-
mao.
1.1 Linguagens de Programao
medida que os computadores foram resolvendo os problemas que lhes fo-
mos colocando, surgiu o interesse de os usarmos para resolver problemas pro-
gressivamente mais complexos. Infelizmente, medida que os problemas se
tornam mais complexos, tambm a sua descrio se torna mais complexa.
Como a descrio do problema e dos passos necessrios para a sua soluo
so responsabilidade dos seres humanos, essas actividades passaram a exigir
a colaborao de vrias pessoas e passaram a exigir, por vezes, quantidades
substanciais de trabalho. Felizmente, o rigor que os computadores exigem
tem a vantagem de permitir tambm aos seres humanos formas rigorosas de
comunicao entre si.
Uma linguagem de programao no apenas um meio de indicar a um
computador uma srie de operaes a executar. Uma linguagem de programa-
o , sobretudo, um meio de descrevermos um processo que, se for seguido,
ir produzir os resultados desejados.
Uma linguagem de programao deve ser feita para seres humanos dialo-
garem acerca de programas e, s incidentalmente, para computadores os exe-
cutarem. Como tal, deve possuir ideias simples, deve ser capaz de combinar
1
Infelizmente, o descuido e, por vezes, a pura irracionalidade tm permitido destruir algu-
mas preciosas coleces de conhecimentos. As sucessivas destruies sofridas pela Biblioteca
de Alexandria so um triste exemplo dos frequentes retrocessos da humanidade.
6
ideias simples para formar ideias mais complexas e deve ser capaz de realizar
abstraces de ideias complexas para as tornar simples.
Existe uma enorme diversidade de linguagens de programao, umas mais
adaptadas a um determinado tipo de processos, outras mais adaptadas a ou-
tros. A escolha de uma linguagem de programao deve estar condicionada,
naturalmente, pelo tipo de problemas que queremos resolver, mas no deve
ser um comprometimento total. Para quem programa muito mais impor-
tante compreender os fundamentos e tcnicas da programao do que domi-
nar esta ou aquela linguagem. No entanto, para mais rigorosamente se expli-
car aqueles fundamentos e tcnicas, convm exemplic-los numa linguagem
de programao concreta.
Neste texto iremos explicar os fundamentos da programao atravs da
utilizao da linguagem Lisp e, mais propriamente, do seu dialecto AutoLisp.
1.2 Lisp
Lisp uma linguagem de programao extremamente simples e exvel. Em-
bora tenha sido inicialmente inventada como uma linguagemmatemtica, cedo
se procedeu sua implementao em diversos computadores, o que os tornou
em executores dos processos descritos nos programas Lisp.
Desde a sua gnese que a linguagem Lisp prima pela enorme facilidade
de extenso. Isto permite ao programador ampliar a linguagem, dotando-a
de novos meios para resolver problemas. Esta capacidade permitiu ao Lisp
sobreviver evoluo da informtica. Embora outras linguagens se tenham
tornado obsoletas, a linguagem Lisp continua activa e a segunda mais antiga
linguagem ainda em utilizao, sendo apenas ultrapassada pela linguagem
Fortran.
A facilidade de utilizao, adaptao e extenso da linguagem fez com
que surgissem dezenas de diferentes dialectos: FranzLisp, ZetaLisp, LeLisp,
MacLisp, InterLisp, Scheme, T, Nil, XLisp e AutoLISP so apenas alguns dos
exemplos mais relevantes. Neste livro iremos debruarmo-nos sobre o dialecto
AutoLISP.
A linguagem AutoLISP derivou da linguagem XLisp e foi incorporada no
AutoCad em 1986, tendo sido intensivamente usada desde ento. Em 1999, o
AutoCad passou a disponibilizar uma verso melhorada do AutoLisp deno-
minada Visual LISP que, entre outras diferenas, possui um compilador para
uma execuo mais eciente e um depurador de programas para facilitar a
deteco e correco de erros. A inuncia do AutoCad to grande que v-
rios outros vendedores decidiram incluir uma implementao de AutoLISP
nos seus prprios produtos, de modo a facilitar a transio de utilizadores.
Um aspecto caracterstico do Lisp ser uma linguagem interactiva. Cada
poro de um programa pode ser desenvolvida, testada e corrigida indepen-
dentemente das restantes. Deste modo, Lisp permite que o desenvolvimento,
teste e correco de programas seja feito de uma forma incremental, o que fa-
cilita muito a tarefa do programador.
Embora os exemplos que iremos apresentar sejam vlidos apenas em Au-
toLISP, falaremos genericamente da linguagem Lisp e, apenas quando neces-
7
srio, mencionaremos o AutoLISP.
1.3 Exerccios
Exerccio 1.3.1 A exponenciao b
n
uma operao entre dois nmeros b e n desig-
nados base e expoente, respectivamente. Quando n um inteiro positivo, a exponen-
ciao dene-se como uma multiplicao repetida:
b
n
= b b b

n
Para um leitor que nunca tenha utilizado o operador de exponenciao, a de-
nio anterior levanta vrias questes cujas respostas podero no lhe ser evidentes.
Quantas multiplicaes so realmente feitas? Sero n multiplicaes? Sero n 1
multiplicaes? O que fazer no caso b
1
? E no caso b
0
?
Proponha uma denio matemtica de exponenciao que no levante estas ques-
tes.
Exerccio 1.3.2 O que uma linguagem de programao? Para que serve?
8
2 Sintaxe, Semntica e Pragmtica
Todas as linguagens possuem sintaxe, semntica e pragmtica.
Em termos muito simples, podemos descrever a sintaxe de uma linguagem
como o conjunto de regras que determinam as frases que se podem construir
nessa linguagem. Sem sintaxe, qualquer concatenao arbitrria de palavras
constituiria uma frase. Por exemplo, dadas as palavras Joo, o, comeu,
e bolo, as regras da sintaxe da lngua Portuguesa dizem-nos que o Joo
comeu o bolo uma frase e que o comeu Joo bolo bolo no uma frase.
Note-se que, de acordo com a sintaxe do Portugus, o bolo comeu o Joo
tambm uma frase sintaticamente correcta.
A sintaxe regula a construo das frases mas nada diz acerca do seu signi-
cado. a semntica de uma linguagem que nos permite atribuir signicado
s frases da linguagem e que nos permite perceber que a frase o bolo comeu
o Joo no faz sentido.
Finalmente, a pragmtica diz respeito forma usual como se escrevem as
frases da linguagem. Para uma mesma linguagem, a pragmtica varia de con-
texto para contexto: a forma como dois amigos ntimos falam entre si dife-
rente da forma usada por duas pessoas que mal se conhecem.
Estes trs aspectos das linguagens esto tambm presentes quando discu-
timos linguagens de programao. Contrariamente ao que acontece com as
linguagens naturais que empregamos para comunicarmos uns com os outros,
as linguagens de programao caracterizam-se por serem formais, obedecendo
a um conjunto de regras muito mais simples e rgido que permite que sejam
analisadas e processadas mecanicamente.
Neste texto iremos descrever a sintaxe e semntica da linguagem Auto
Lisp. Embora existam formalismos matemticos que permitem descrever ri-
gorosamente aqueles dois aspectos das linguagens, eles exigem uma sostica-
o matemtica que, neste trabalho, desapropriada. Por este motivo, iremos
apenas empregar descries informais.
Quanto pragmtica, esta ser explicada medida que formos introdu-
zindo os elementos da linguagem. A linguagem Auto Lisp promove uma
pragmtica que, nalguns aspectos, difere signicativamente do que habi-
tual nos restantes dialectos de Lisp. Uma vez que a pragmtica no inuencia
a correco dos nossos programas mas apenas o seu estilo, iremos empregar
uma pragmtica ligeiramente diferente da usual em Auto Lisp mas que pen-
samos ser mais apropriada.
2.1 Sintaxe e Semntica do Lisp
Quando comparada com a grande maioria das outras linguagens de progra-
mao, a linguagem Lisp possui uma sintaxe extraordinariamente simples ba-
seada no conceito de expresso.
2
Uma expresso, em Lisp, pode ser construda empregando elementos pri-
mitivos como, por exemplo, os nmeros; ou combinando outras expresses
2
Originalmente, Lisp dizia-se baseado em S-expression, uma abreviatura para expresses
simblicas. Esta caracterizao ainda aplicvel mas, por agora, no a vamos empregar.
9
entre si como, por exemplo, quando somamos dois nmeros. Como iremos
ver, esta simples denio permite-nos construir expresses de complexidade
arbitrria. No entanto, convm relembrarmos que a sintaxe restringe aquilo
que podemos escrever: o facto de podermos combinar expresses para pro-
duzir outras expresses mais complexas no nos autoriza a escrever qualquer
combinao de subexpresses. As combinaes obedecem a regras sintticas
que iremos descrever ao longo do texto.
semelhana do que acontece com a sintaxe, tambm a semntica da lin-
guagem Lisp , em geral, substancialmente mais simples que a de outras lin-
guagens de programao. Como iremos ver, a semntica determinada pelos
operadores que as nossas expresses iro empregar. Um operador de soma, por
exemplo, serve para somar dois nmeros. Uma combinao que junte este
operador e, por exemplo, os nmeros 3 e 4 tem, como signicado, a soma de
3 com 4, i.e., 7. No caso das linguagens de programao, a semntica de uma
expresso dada pelo computador que a vai avaliar.
2.2 O Avaliador
Em Lisp, qualquer expresso tem um valor. Este conceito de tal modo impor-
tante que todas as implementaes da linguagem Lisp apresentam um avalia-
dor, i.e., umprograma destinado a interagir como utilizador de modo a avaliar
expresses por este fornecidas.
No caso do AutoCad, o avaliador est contido num ambiente interactivo
de desenvolvimento, denominado Visual Lisp e pode ser acedido atravs de
menus (menu Tools, submenu AutoLISP, item Visual LISP Editor) ou
atravs do comando vlisp. Uma vez acedido o Visual Lisp, o utilizador en-
contrar uma janela com o ttulo Visual LISP Console e que se destina preci-
samente interaco com o avaliador de Auto Lisp.
Assim, quando o utilizador comea a trabalhar com o Lisp, -lhe apresen-
tado um sinal (denominado prompt) e o Lisp ca espera que o utilizador
lhe fornea uma expresso.
_$
O texto _$ a prompt do Lisp, frente da qual vo aparecer as ex-
presses que o utilizador escrever. O Lisp interacciona com o utilizador exe-
cutando um ciclo em que l uma expresso, determina o seu valor e escreve o
resultado. Este ciclo de aces designa-se, tradicionalmente, de read-eval-print-
loop (e abrevia-se para REPL).
Quando o Lisp l uma expresso, constroi internamente um objecto que
a representa. Esse o papel da fase de leitura. Na fase de avaliao, o ob-
jecto construdo analisado de modo a produzir um valor. Esta anlise feita
empregando as regras da linguagem que determinam, para cada caso, qual o
valor do objecto construdo. Finalmente, o valor produzido apresentado ao
utilizador na fase de escrita atravs de uma representao textual desse valor.
Dada a existncia do read-eval-print-loop, em Lisp no necessrio instruir o
computador a escrever explicitamente os resultados de um clculo como acon-
tece noutras linguages como, por exemplo, em Java. Isto permite que o teste
10
e correco de erros seja bastante facilitada. A vantagem de Lisp ser uma lin-
guagem interactiva est na rapidez com que se desenvolvem prottipos de
programas, escrevendo, testando e corrigindo pequenos fragmentos de cada
vez.
Exerccio 2.2.1 O que o REPL?
3 Elementos da Linguagem
Em qualquer linguagem de programao precisamos de lidar com duas es-
pcies de objectos: dados e procedimentos. Os dados so as entidades que
pretendemos manipular. Os procedimentos so descries das regras para ma-
nipular esses dados.
Se considerarmos a linguagem da matemtica, podemos identicar os n-
meros como dados e as operaes algbricas como procedimentos. As ope-
raes algbricas permitem-nos combinar os nmeros entre si. Por exemplo,
2 2 uma combinao. Uma outra combinao envolvendo mais dados ser
2 2 2 e, usando ainda mais dados, 2 2 2 2. No entanto, a menos que
pretendamos car eternamente a resolver problemas de aritmtica elementar,
convm considerar operaes mais elaboradas que representam padres de
clculos. Na sequncia de combinaes que apresentmos evidente que o
padro que est a emergir o da operao de potenciao, i.e, multiplicao
sucessiva, tendo esta operao sido denida na matemtica h j muito tempo.
A potenciao , portanto, uma abstraco de uma sucesso de multiplicaes.
Tal como a linguagem da matemtica, uma linguagem de programao
deve possuir dados e procedimentos primitivos, deve ser capaz de combinar
quer os dados quer os procedimentos para produzir dados e procedimentos
mais complexos e deve ser capaz de abstrair padres de clculo de modo a
permitir trat-los como operaes simples, denindo novas operaes que re-
presentem esses padres de clculo.
Mais frente iremos ver como possvel denir essas abstraces em Lisp
mas, por agora, vamos debruar-nos sobre os elementos mais bsicos, os cha-
mados elementos primitivos da linguagem.
3.1 Elementos primitivos
Elementos primitivos so as entidades mais simples comque a linguagemlida.
Os elementos primitivos podem ser divididos em dados primitivos e procedi-
mentos primitivos. Um nmero, por exemplo, um dado primitivo.
3.1.1 Nmeros
Como dissemos anteriormente, o Lisp executa um ciclo read-eval-print. Isto
implica que tudo o que escrevemos no Lisp tem de ser avaliado, i.e., tem de
ter um valor, valor esse que o Lisp escreve no cran.
11
Assim, se dermos um nmero ao avaliador, ele devolve-nos o valor desse
nmero. Quanto vale um nmero? O melhor que podemos dizer que ele
vale por ele prprio. Por exemplo, o nmero 1 vale 1.
_$ 1
1
_$ 12345
12345
_$ 4.5
4.5
Como se v no exemplo, em Lisp, os nmeros podem ser inteiros ou reais.
Os reais so nmeros com um ponto decimal e, no caso do Auto Lisp, tem de
haver pelo menos um dgito antes do ponto decimal:
_$ 0.1
0.1
_$ .1
; error: misplaced dot on input
Note-se, no exemplo anterior, que o Auto Lisp produziu um erro. Um erro
uma situao anmala que impede o Auto Lisp de prosseguir o que estava a
fazer. Neste caso, apresentada uma mensagem de erro e o Auto Lisp volta ao
princpio do ciclo read-eval-print.
Exerccio 3.1.1 Descubra qual o maior real e o maior inteiro que o seu Lisp aceita.
Exerccio 3.1.2 Em matemtica, usal empregar simultaneamente as diferentes nota-
es prexa, inxa e posxa. Escreva exemplos de expresses matemticas que utili-
zem estas diferentes notaes.
Exerccio 3.1.3 Converta as seguintes expresses da notao inxa da aritmtica para
a notao prexa do Lisp:
1. 1 + 2 3
2. 1 2 3
3. 1 2 3
4. 1 2 3
5. (1 2) 3
6. (1 2) + 3
7. 1 (2 + 3)
8. 2 2 + 3 3 3
Exerccio 3.1.4 Converta as seguintes expresses da notao prexa do Lisp para a
notao inxa da aritmtica:
1. (
*
(/ 1 2) 3)
2. (
*
1 (- 2 3))
12
3. (/ (+ 1 2) 3)
4. (/ (/ 1 2) 3)
5. (/ 1 (/ 2 3))
6. (- (- 1 2) 3)
7. (- 1 2 3)
Exerccio 3.1.5 Indente a seguinte expresso de modo a ter um nico operando por
linha.
(
*
(+ (/ 3 2) (- (
*
(/ 5 2) 3) 1) (- 3 2)) 2)
3.2 Avaliao de Combinaes
Como j vimos, o Lisp considera que o primeiro elemento de uma combinao
um operador e os restantes so os operandos.
O avaliador determina o valor de uma combinao como o resultado de
aplicar o procedimento especicado pelo operador ao valor dos operandos. O
valor de cada operando designado de argumento do procedimento. Assim, o
valor da combinao (+ 1 (
*
2 3)) o resultado de somar o valor de 1 com
o valor de (
*
2 3). Como j se viu, 1 vale 1 e (
*
2 3) uma combinao
cujo valor o resultado de multiplicar o valor de 2 pelo valor de 3, o que d 6.
Finalmente, somando 1 a 6 obtemos 7.
_$ (
*
2 3)
6
_$ (+ 1 (
*
2 3))
7
Uma diferena importante entre o Auto Lisp e a aritmtica ocorre na ope-
rao de diviso. Matematicamente falando, 7/2 uma fraco, i.e., no
um nmero inteiro. Infelizmente, o Auto Lisp no sabe lidar com fraces e,
consequentemente, emprega uma denio ligeiramente diferente para o ope-
rador de diviso: em Auto Lisp, o smbolo / representa a diviso inteira, i.e.,
o nmero que multiplicado pelo divisor e somado ao resto iguala o dividendo.
Assim, (/ 7 2) avalia para 3. No entanto, quando est a lidar com nmeros
reais, o Auto Lisp j faz a diviso segundo as regras da matemtica mas, pos-
sivelmente, envolvendo perdas de preciso. Assim, (/ 7.0 2) produz 3.5.
Exerccio 3.2.1 Calcule o valor das seguintes expresses Lisp:
1. (
*
(/ 1 2) 3)
2. (
*
1 (- 2 3))
3. (/ (+ 1 2) 3)
4. (- (- 1 2) 3)
5. (- 1 2 3)
6. (- 1)
13
3.3 Operadores de Strings
Para alm dos operadores que j vimos para nmeros, existem operadores
para strings. Por exemplo, para concatenar vrias strings, existe o operador
strcat. A concatenao de vrias strings produz uma s string com todos os
caracteres dessas vrias strings e pela mesma ordem:
_$ (strcat "1" "2")
"12"
_$ (strcat "um" "dois" "tres" "quatro")
"umdoistresquatro"
_$ (strcat "eu" " " "sou" " " "uma" " " "string")
"eu sou uma string"
_$ (strcat "E eu" " sou " "outra")
"E eu sou outra"
Para saber o nmero de caracteres de uma string existe o operador strlen:
_$ (strlen (strcat "eu" " " "sou" " " "uma" " " "string"))
17
_$ (strlen "")
0
Note-se que as aspas so os delimitadores de strings e no contam como
caracteres.
A funo substr providencia uma terceira operao til com strings: ela
permite obter parte de uma string. A parte a obter especicada atravs da
posio do primeiro carcter e do nmero de caracteres a considerar. Numa
string, a posio de um carcter tambm denominada de ndice do caracter.
O Auto Lisp considera que o primeiro carcter de uma string tem o ndice 1.
A funo substr recebe, como argumentos, uma string, um ndice e, opcio-
nalmente, um nmero de caracteres e devolve a parte da string que comea no
ndice dado e que tem o nmero de caracteres dado no parmetro opcional ou
todos os restantes caracteres no caso de esse nmero no ter sido dado. Assim,
temos:
_$ (substr "abcd" 1)
"abcd"
_$ (substr "abcd" 2)
"bcd"
_$ (substr "abcd" 2 2)
"bc"
Exerccio 3.3.1 Qual o resultado das seguintes avaliaes?
1. (strcat "a" "vista" "da" " baixa" "da" " banheira")
2. (substr (strcat "Bom dia") 1 3)
3. (substr (strcat "Bom dia") 5)
14
3.4 Denio de Funes
Para alm das operaes bsicas aritmticas, a matemtica disponibiliza-nos
um vastssimo conjunto de outras operaes que se denem custa daquelas.
Por exemplo, o quadrado de um nmero uma operao (tambm designada
por funo) que, dado um nmero, produz o resultado de multiplicar esse n-
mero por ele prprio. Matematicamente falando, dene-se o quadrado de um
nmero pela funo x
2
= x x.
Tal como em matemtica, pode-se denir numa linguagem de programa-
o a funo que obtm o quadrado de um nmero. Em Lisp, para obtermos o
quadrado de um nmero qualquer, por exemplo, 5, escrevemos a combinao
(
*
5 5). No caso geral, dado um nmero qualquer x, sabemos que obtemos
o seu quadrado escrevendo (
*
x x). Falta apenas associar um nome que in-
dique que, dado um nmero x, obtemos o seu quadrado avaliando (
*
x x).
Lisp permite-nos fazer isso atravs da operao defun (abreviatura de define
function):
_$ (defun quadrado (x) (
*
x x))
QUADRADO
Note-se que o Auto Lisp, ao avaliar a denio da funo quadrado de-
volve como valor o nome da funo denida. Note-se ainda que o Auto Lisp
escreve esse nome em maisculas. Na realidade, o que se passa que, por mo-
tivos histricos, todos os nomes que escrevemos no Auto Lisp so traduzidos
para maisculas assim que so lidos. Por este motivo, quadrado, QUADRADO,
Quadrado, qUaDrAdo, ou qualquer outra combinao de maisculas e mins-
culas designa o mesmo nome em Auto Lisp: QUADRADO. Apesar da converso
para maisculas que feita na leitura, pragmtica usual escrevermos os nos-
sos programas em letras minsculas.
Como se pode ver pela denio da funo quadrado, para se denirem
novos procedimentos em Lisp, necessrio criar uma combinao de quatro
elementos. O primeiro elemento desta combinao a palavra defun, que in-
forma o avaliador que estamos a denir uma funo. O segundo elemento o
nome da funo que queremos denir, o terceiro elemento uma combinao
com os parmetros da funo e o quarto elemento a expresso que deter-
mina o valor da funo para aqueles parmetros. De modo genrico podemos
indicar que a denio de funes feita usando a seguinte forma:
(defun nome (parmetro
1
... parmetro
n
)
corpo)
Quando se d uma expresso desta forma ao avaliador, ele acrescenta a
funo ao conjunto de funes da linguagem, associando-a ao nome que lhe
demos e devolve como valor da denio o nome da funo denida. Se j
existir uma funo com o mesmo nome, a denio anterior simplesmente
esquecida. Os parmetros de um procedimento so designados parmetros
formais e so os nomes usados no corpo de expresses para nos referirmos
aos argumentos correspondentes. Quando escrevemos no avaliador de Lisp
15
(quadrado 5), 5 o argumento do procedimento. Durante o clculo da fun-
o este argumento est associado ao parmetro formal x. Os argumentos de
uma funo so tambm designados por parmetros actuais.
No caso da funo quadrado, a sua denio diz que para se determinar o
quadrado de um nmero x, devemos multiplicar esse nmero por ele prprio
(
*
x x). Esta denio associa a palavra quadrado a um procedimento, i.e.,
a uma descrio do modo de produzir o resultado pretendido. Note-se que
este procedimento possui parmetros, permitindo o seu uso com diferentes
argumentos. Para se utilizar este procedimento, podemos avaliar as seguinte
expresses:
_$ (quadrado 5)
25
_$ (quadrado 6)
36
A regra de avaliao de combinaes que descrevemos anteriormente
tambm vlida para as funes por ns denidas. Assim, a avaliao da ex-
presso (quadrado (+ 1 2)) passa pela avaliao do operando (+ 1 2).
Este operando tem como valor 3, valor esse que usado pela funo no lu-
gar do parmetro x. O corpo da funo ento avaliado mas substituindo
todas as ocorrncias de x pelo valor 3, i.e., o valor nal ser o da combinao
(
*
3 3).
Para se perceber a avaliao de combinaes que o Lisp emprega, til de-
compor essa avaliao nas suas etapas mais elementares. No seguinte exemplo
mostramos o processo de avaliao para a expresso
(quadrado (quadrado (+ 1 2)))
Em cada passo, uma das sub-expresses foi avaliada.
(quadrado (quadrado (+ 1 2)))

(quadrado (quadrado 3))

(quadrado (
*
3 3))

(quadrado 9)

(
*
9 9)

81
Como dissemos, a denio de funes permite-nos associar um procedi-
mento a um nome. Isto implica que o Lisp tem de possuir uma memria onde
possa guardar a funo e a sua associao ao nome dado. Esta memria do
Lisp designa-se ambiente.
16
Note-se que este ambiente apenas existe enquanto estamos a trabalhar com
a linguagem. Quando terminamos, perde-se todo o ambiente. Para evitar per-
dermos as denies de procedimentos que tenhamos feito, convm regist-
las num suporte persistente, como seja um cheiro. Para facilitar a utilizao,
o Lisp permite que se avaliem as diversas denies a partir de um cheiro.
Por este motivo, o processo usual de trabalho com Lisp consiste em escrever
as vrias denies em cheiros embora se continue a usar o avaliador de Lisp
para experimentar e testar o correcto funcionamento das nossas denies.
Exerccio 3.4.1 Dena a funo dobro que, dado um nmero, calcula o seu dobro.
3.5 Smbolos
A denio de funes em Lisp passa pela utilizao de nomes: nomes para as
funes e nomes para os parmetros das funes.
Uma vez que o Lisp, antes de avaliar qualquer expresso, tem de a ler e
converter internamente para um objecto, tambm cada nome que escrevemos
convertido na leitura para um determinado objecto. Esse objecto designado
por smbolo. Um smbolo , pois, a representao interna de um nome e outro
dos elementos primitivos da linguagem.
Em Lisp, quase no existem limitaes para a escrita de nomes. Um nome
como quadrado to vlido como + ou como 1+2
*
3 pois o que separa um
nome dos outros elementos de uma combinao so apenas parnteses e es-
pao em branco.
3
Por exemplo, perfeitamente correcto denir e usar a se-
guinte funo:
_$ (defun x+y
*
z (x y z)
(+ x (
*
y z)))
X+Y
*
Z
_$ (x+y
*
z 1 2 3)
7
No caso do Auto Lisp, os nicos caracteres que no se podem utilizar nos
nomes dos smbolos so o abrir e fechar parnteses ( e ), a plica (tambm
chamada apstrofo) , as aspas ", o ponto . e o ponto e vrgula ;. Todos os
restantes caracteres se podem usar para nomes de funes mas, na prtica, a
criao de nome segue algumas regras que convm ter presente:
Apenas se devem usar as letras do alfabeto, os dgitos, os smbolos arit-
mticos e alguns caracteres de pontuao, como o ponto, o ponto de ex-
clamao e o ponto de interrogao. Por motivos de portabilidade, con-
vm evitar o uso de caracteres acentuados.
Se o nome da funo composto por vrias palavras, deve-se separar
as palavras com traos (-). Por exemplo, uma funo que calcula a rea
de um crculo poder ter como nome o smbolo area-circulo. J os
3
Dentro do conceito de espao em branco consideram-se os caracteres de espao, de tabu-
lao e de mudana de linha.
17
nomes areacirculo, area_circulo e area+circulo sero menos
apropriados.
Se o nome corresponde a uma interrogao, deve-se terminar o nome
com um ponto de interrogao (?) ou, na tradio Lisp, com a letra p.
4
Por exemplo, uma funo que indica se um nmero par poder ter o
nome par?.
Se a funo faz uma converso entre dois tipos de valores, o nome poder
ser obtido a partir dos nomes dos tipos com uma seta entre eles a indicar
a direco da converso. Por exemplo, uma funo que converte euros
para libras poder ter como nome euros->libras ou, ainda melhor,
libras<-euros.
Exerccio 3.5.1 Indique um nome apropriado para cada uma das seguintes funes:
1. Funo que calcula o volume de uma esfera.
2. Funo que indica se um nmero primo.
3. Funo que converte uma medida em centmetros para polegadas.
3.6 Avaliao de Smbolos
Vimos que todos os outros elementos primitivos que apresentmos at agora,
nomeadamente, os nmeros e as cadeias de caracteres avaliavam para eles
prprios, i.e., o valor de uma expresso composta apenas por um elemento
primitivo o prprio elemento primitivo. No caso dos smbolos, isso j no
verdade.
Lisp atribui um signicado muito especial aos smbolos. Reparemos que,
quando denimos uma funo, o nome da funo um smbolo. Os par-
metros formais da funo tambm so smbolos. Quando escrevemos uma
combinao, o avaliador de Lisp usa a denio de funo que foi associada
ao smbolo que constitui o primeiro elemento da combinao. Isto quer dizer
que o valor do primeiro smbolo de uma combinao a funo que lhe est
associada. Admitindo que tnhamos denido a funo quadrado tal como vi-
mos na seco 3.4, podemos vericar este comportamento experimentando as
seguintes expresses:
_$ (quadrado 3)
9
_$ quadrado
#<USUBR @1d4c66f4 QUADRADO>
Como se pode ver pelo exemplo anterior, o valor do smbolo quadrado
uma entidade que o Lisp descreve usando uma notao especial. A entidade
4
Esta letra a abreviatura de predicado, um tipo de funo que iremos estudar mais frente.
18
emquesto , como vimos, uma funo. Omesmo comportamento ocorre para
qualquer outra funo pr-denida na linguagem:
5
_$ +
#<SUBR @0a87c5a8 +>
_$
*
#<SUBR @0a87c588
*
>
Como vimos com o + e o
*
, alguns dos smbolos esto pr-denidos na
linguagem. Por exemplo, o smbolo PI tambm existe pr-denido com uma
aproximao do valor de .
_$ pi
3.141519
No entanto, quando o avaliador est a avaliar o corpo de uma funo, o va-
lor de um smbolo especicado nos parmetros da funo o argumento cor-
respondente na invocao da funo. Assim, na combinao (quadrado 3),
depois de o avaliador saber que o valor de quadrado a funo por ns de-
nida atrs e que o valor de 3 3, o avaliador passa a avaliar o corpo da funo
quadrado mas assumindo que, durante essa avaliao, o nome x, sempre que
for necessrio, ir ter como valor precisamente o mesmo 3 que foi associado
ao parmetro x.
Exerccio 3.6.1 Dena a funo radianos<-graus que recebe uma quantidade an-
gular em graus e calcula o valor correspondente em radianos. Note que 180 graus
correspondem a radianos.
Exerccio 3.6.2 Dena a funo graus<-radianos que recebe uma quantidade an-
gular em radianos e calcula o valor correspondente em graus.
Exerccio 3.6.3 Dena a funo que calcula o permetro de uma circunferncia de raio
r.
3.7 Funes de Mltiplos Parmetros
J vimos e denimos vrias funes em Lisp. At agora, todas as que deni-
mos tinham um nico parmetro mas, obviamente, possvel denir funes
com mais do que um parmetro.
Por exemplo, a rea A de um tringulo de base b e altura c dene-se mate-
maticamente por A(b, c) =
bc
2
. Em Lisp, teremos:
(defun A (b c) (/ (
*
b c) 2))
5
Um olhar mais atento encontrar uma pequena diferena: no caso do quadrado, a funo
associada do tipo USUBR enquanto que nos casos do + e
*
as funes associadas so do tipo
SUBR. A diferena entre estes dois tipos est relacionada com o facto de as SUBRs estarem com-
piladas, permitindo a sua invocao de forma mais eciente. O termo SUBR uma abreviatura
de subroutine.
19
Como se pode ver, a denio da funo em Lisp idntica denio
correspondente em Matemtica, com a diferena de os operadores se usarem
de forma prexa e o smbolo de denio matemtica = se escrever defun.
No entanto, contrariamente ao que usual ocorrer em Matemtica, os nomes
que empregamos em Lisp devem ter um signicado claro. Assim, ao invs de
se escrever A prefervel escrever area-triangulo. Do mesmo modo, ao
invs de se escrever b e c, seria prefervel escrever base e altura. Tendo
estes aspectos em conta, podemos apresentar uma denio mais legvel:
(defun area-triangulo (base altura)
(/ (
*
base altura) 2))
Quando o nmero de denies aumenta torna-se particularmente impor-
tante para quem as l que se perceba rapidamente o seu signicado e, por isso,
de crucial importncia que se faa uma boa escolha de nomes.
Exerccio 3.7.1 Dena uma funo que calcula o volume de um paralelippedo. Em-
pregue nomes sucientemente claros.
Exerccio 3.7.2 Dena uma funo que calcula o volume de um elipside de semi-
eixos a, b e c. Esse volume pode ser obtido pela frmula V =
4
3
abc.
3.8 Encadeamento de Funes
Todas funes por ns denidas so consideradas pelo avaliador de Lisp em
p de igualdade com todas as outras denies. Isto permite que elas possam
ser usadas para denir ainda outras funes. Por exemplo, aps termos de-
nido a funo quadrado, podemos denir a funo que calcula a rea de um
crculo de raio r atravs da frmula r
2
.
(defun area-circulo (raio)
(
*
pi (quadrado raio)))
Durante a avaliao de uma expresso destinada a computar a rea de um
crculo, a funo quadrado acabar por ser invocada. Isso visvel na se-
guinte sequncia de passos de avaliao:
(area-circulo 2)
(
*
pi (quadrado 2))
(
*
3.141519 (quadrado 2))
(
*
3.141519 (
*
2 2))
(
*
3.141519 4)
12.566076
Exerccio 3.8.1 Dena a funo que calcula o volume de um cilindro com um deter-
minado raio e comprimento. Esse volume corresponde ao produto da rea da base
pelo comprimento do cilindro.
20
3.9 Funes Pr-Denidas
A possibilidade de se denirem novas funes fundamental para aumentar-
mos a exibilidade da linguagem e a sua capacidade de se adaptar aos proble-
mas que pretendemos resolver. As novas funes, contudo, precisam de ser
denidas custa de outras que, ou foram tambm por ns denidas ou, no
limite, j estavam pr-denidas na linguagem.
Isto mesmo se verica no caso da funo area-circulo que denimos
acima: ela est denida custa da funo quadrado (que foi tambm por
ns denida) e custa da operao de multiplicao. No caso da funo
quadrado, ela foi denida com base na operao de multiplicao. A ope-
rao de multiplicao que, em ltima anlise, a base do funcionamento da
funo area-circulo , na realidade, uma funo pr-denida do Lisp.
Como iremos ver, Lisp providencia um conjunto razoavelmente grande de
funes pr-denidas. Em muitos casos, elas so sucientes para o que preten-
demos mas, emgeral, no nos devemos coibir de denir novas funes sempre
que acharmos necessrio.
A Tabela 1 apresenta uma seleco de funes matemticas pr-denidas
do Auto Lisp. Note-se que, devido s limitaes sintticas do Auto Lisp (e que
so comuns a todas as outras linguagens de programao), h vrios casos em
que uma funo em Auto Lisp emprega uma notao diferente daquela que
usual em matemtica. Por exemplo,

x escreve-se como (sqrt x). O nome
sqrt uma contraco do Ingls square root e contraces semelhantes so
empregues para vrias outras funes. Por exemplo, a funo [x[ escreve-se
(abs x) (de absolute value), com x| que se escreve (fix x) (de xed point)
ou com x
y
que se escreve (expt x y) (de exponential).
A Tabela 2 apresenta uma seleco de funes sobre strings pr-denidas
do Auto Lisp. medida que formos apresentando novos tpicos do Auto Lisp
iremos explicando outras funes pr-denidas que sejam relevantes para o
assunto.
Exerccio 3.9.1 Embora o seno (sin) e o cosseno (cos) sejam funes pr-denidas
em Auto Lisp, a tangente (tan) no . Dena-a a partir da frmula tanx =
sin x
cos x
.
Exerccio 3.9.2 Do conjunto das funes trigonomtricas inversas, o Auto Lisp apenas
providencia o arco tangente (atan). Dena tambm as funes arco-seno (asin) e
arco-cosseno (acos), cujas denies matemticas so:
asinx = atan
x

1 x
2
acos x = atan

1 x
2
x
Exerccio 3.9.3 Traduza as seguintes expresses matemticas para Auto Lisp:
1.

1
log 2
|(39 log 25)|
2.
cos
4 2

5
atan 3
3.
1
2
+

3 + sin
5
2
2
21
Exerccio 3.9.4 Traduza as seguintes expresses Auto Lisp para a notao matem-
tica:
1. (log (sin (+ (expt 2 4) (/ (fix (atan pi)) (sqrt 5)))))
2. (expt (cos (cos (cos 0.5))) 5)
3. (sin (/ (cos (/ (sin (/ pi 3)) 3)) 3))
Exerccio 3.9.5 Dena o predicado impar? que, dado um nmero, testa de ele m-
par, i.e., se o resto da diviso desse nmero por dois um. Para calcular o resto da
diviso de um nmero por outro, utilize a funo pr-denida rem.
Exerccio 3.9.6 Em vrias actividades usual empregarem-se expresses padroniza-
das. Por exemplo, se o aluno Passos Dias Aguiar pretende obter uma certido de
matrcula da universidade que frequenta, ter de escrever uma frase da forma:
Passos Dias Aguiar vem respeitosamente pedir a V. Exa. que se digne
passar uma certido de matrcula.
Por outro lado, se a aluna Maria Gustava dos Anjos pretende um certicado de
habilitaes, dever escrever:
Maria Gustava dos Anjos vem respeitosamente pedir a V. Exa. que se
digne passar um certicado de habilitaes.
Para simplicar a vida destas pessoas, pretende-se que implemente uma fun-
o denominada requerimento que, convenientemente parameterizada, gera uma
string coma frase apropriada para qualquer umdos ns anteriormente exemplicados
e tambm para outros do mesmo gnero que possam vir a ser necessrios. Teste a sua
funo para garantir que consegue reproduzir os dois exemplos anteriores passando
o mnimo de informao nos argumentos da funo.
Exerccio 3.9.7 Tambm na actividade da Arquitectura, usual os projectos necessi-
tarem de informaes textuais escritas numa forma padronizada. Por exemplo, con-
sidere as seguintes trs frases contidas nos Cadernos de Encargos de trs diferentes
projectos:
Toda a caixilharia ser metlica, de alumnio anodizado, cor natural,
construda com os pers utilizados pela Serralharia do Corvo (ou seme-
lhante), sujeitos a aprovao da Fiscalizao.
Toda a caixilharia ser metlica, de alumnio lacado, cor branca, cons-
truda com os pers utilizados pela Technal (ou semelhante), sujeitos a
aprovao da Fiscalizao.
Toda a caixilharia ser metlica, de ao zincado, preparado com pri-
mrios de aderncia, primrio epoxdico de proteco e acabamento com
esmalte SMP, cor 1050-B90G (NCS), construda com os pers standard
existentes no mercado, sujeitos a aprovao da Fiscalizao.
Dena uma funo que, convenientemente parameterizada, gera a string ade-
quada para os trs projectos anteriores, tendo o cuidado de a generalizar para qual-
quer outra situao do mesmo gnero.
22
+
2147483648 2 1 0 +1 +2 +2147483647
2
1
0
+1
+2
+2147483647
2147483648
Figura 1: A recta innita dos inteiros empregue em aritmtica e o crculo dos
inteiros modulares empregues em Auto Lisp.
3.10 Aritmtica de Inteiros em Auto Lisp
Vimos que o Auto Lisp disponibiliza, para alm dos operadores aritmticos
usuais, um conjunto de funes matemticas. No entanto, h que ter em conta
que existem diferenas substanciais entre o signicado matemtico destas ope-
raes e a sua implementao no Auto Lisp.
Um primeiro problema importante tem a ver com a gama de inteiros. Em
Auto Lisp, os inteiros so representados com apenas 32 bits de informao.
8
Isto implica que apenas se conseguem representar inteiros desde 2147483647
at 2147483647. Para tornar a situao ainda mais problemtica, embora exista
esta limitao, quando ela no respeitada o Auto Lisp no emite qualquer
aviso. Este comportamento usual na maioria das linguagens de programao
e est relacionado com questes de performance.
9
Infelizmente, a performance
tem como preo o poder originar resultados aparentemente bizarros:
_$ (+ 2147483647 1)
-2147483648
Este resultado surge porque no Auto Lisp, na realidade, as operaes arit-
mticas com inteiros so modulares. Isto implica que a sequncia dos inteiros
no corresponde a uma linha innita nas duas direco, antes correspondendo
a um crculo em que a seguir ao maior nmero inteiro positivo aparece o me-
nor nmero inteiro negativo. Este comportamento encontra-se explicado na
Figura 1.
Um segundo problema que j referimos anteriormente est no facto de o
Auto Lisp no saber representar fraces. Isto implica que uma diviso de
dois inteiros no corresponde diviso matemtica mas sim a uma operao
8
Em AutoCad, a gama de inteiros ainda mais pequena pois a sua representao apenas usa
16 bits, permitindo apenas representar os inteiros de 32768 a 32767. Isto no afecta o Auto
Lisp excepto quando este tem de passar inteiros para o AutoCad.
9
Curiosamente, a maioria dos dialectos de Lisp (mas no o Auto Lisp) no apresenta este
comportamento, preferindo representar nmeros inteiros com dimenso to grande quanto for
necessrio.
23
substancialmente diferente denominada diviso inteira: uma diviso em que
a parte fraccional do resultado eliminada, i.e., apenas se considera o quoci-
ente da diviso, eliminando-se o resto. Assim, (/ 7 2) 3 e no 7/2 ou 3.5.
Obviamente, isto inviabiliza algumas equivalncias matemticas bvias. Por
exemplo, embora
1
3
3 = 1, em Auto Lisp temos:
_$ (
*
(/ 1 3) 3)
0
Finalmente, um terceiro problema que ocorre com os inteiros que a leitura
de um nmero inteiro que excede a gama dos inteiros implica a sua converso
automatica para o tipo real.
10
Neste caso, o avaliador do Auto Lisp nunca
chega a ver o nmero inteiro pois ele foi logo convertido para real na leitura.
Esse comportamento visvel no seguinte exemplo:
_$ 1234567890
1234567890
_$ 12345678901
1.23457e+010
Tambm este aspecto do Auto Lisp pode ser fonte de comportamentos bi-
zarros, tal como demonstrado pelo seguinte exemplo:
_$ (+ 2147483646 1)
2147483647
_$ (+ 2147483647 1)
-2147483648
_$ (+ 2147483648 1)
2.14748e+009
importante salientar que a converso de inteiro para real que visvel na
ltima interaco feita logo na leitura.
Exerccio 3.10.1 Explique o seguinte comportamento do Auto Lisp:
11
_$ (- -2147483647 1)
-2147483648
_$ (- -2147483648 1)
-2.14748e+009
_$ (- -2147483647 2)
2147483647
10
Note-se que estamos apenas a falar da leitura de nmeros. Como j vimos, as operaes
aritmticas usuais no apresentam este comportamento.
11
Este exemplo mostra que, em Auto Lisp, h um inteiro que no pode ser lido mas que
pode ser produzido como resultado de operaes aritmticas. importante salientar que este
comportamento verdadeiramente bizarro exclusivo do Auto Lisp e no se verica em mais
nenhum dialecto de Lisp.
24
3.11 Aritmtica de Reais em Auto Lisp
Em relao aos reais, o seu comportamento mais prximo do que se consi-
dera matematicamente correcto mas, ainda assim, h vrios problemas com
que preciso lidar.
A gama dos reais vai desde 4.94066 10
324
at 1.79769 10
+308
. Se o
Auto Lisp tentar ler umnmero real que excede esta gama ele imediatamente
convertido para um nmero especial que representa o innito:
_$ 2e400
1.#INF
_$ -2e400
-1.#INF
Note-se que 1.#INF ou -1.#INF a forma do Auto Lisp indicar um valor
que excede a capacidade de representao de reais do computador. No
innito, como se poderia pensar, mas apenas um valor excessivamente grande
para as capacidades do Auto Lisp. Do mesmo modo, quando alguma operao
aritmtica produz um nmero que excede a gama dos reais, simplesmente
gerada a representao do innito.
_$ 1e300
1.0e+300
_$ 1e100
1.0e+100
_$ (
*
1e300 1e100)
1.#INF
Nestes casos, em que o resultado de uma operao um nmero que ex-
cede as capacidades da mquina, dizemos que ocorreu um overow.
As operaes com nmeros reais tm a vantagem de a maioria dos compu-
tadores actuais conseguirem detectar o overow de reais e reagirem em confor-
midade (gerando umerro ou simplesmente produzindo uma representao do
innito). Como vimos anteriormente, se se tivessem usado nmeros inteiros,
ento o overow no seria sequer detectado, produzindo comportamentos apa-
rentemente bizarros, como, por exemplo, o produto de dois nmeros positivos
ser um nmero negativo.
H ainda dois outros problemas importantes relacionados com reais: erros
de arredondamento e reduo de preciso na escrita. A ttulo de exemplo,
consideremos a bvia igualdade matemtica (
4
3
1) 3 1 = 0 e comparemos
os resultados que se obtm usando inteiros ou reais:
_$ (- (
*
(- (/ 4 3) 1) 3) 1)
-1
_$ (- (
*
(- (/ 4.0 3.0) 1.0) 3.0) 1.0)
-2.22045e-016
Como se pode ver, nem usando inteiros, nem usando reais, se consegue
obter o resultado correcto. No caso dos inteiros, o problema causado pela
25
diviso inteira de 4 por 3 que produz 1. No caso dos reais, o problema cau-
sado por erros de arrendondamento: 4/3 no representvel com um nmero
nito de dgitos. Este erro de arrendondamento ento propagado nas res-
tantes operaes produzindo um valor que, embora no seja zero, est muito
prximo.
Obviamente, como o resultado da avaliao com reais sucientemente
pequeno, podemos convert-lo para o tipo inteiro (aplicando-lhe uma trunca-
tura com a funo fix) e obtemos o resultado correcto:
_$ (fix (- (
*
(- (/ 4.0 3.0) 1.0) 3.0) 1.0))
0
No entanto, esta soluo tambm tem problemas. Consideremos a divi-
so 0.6/0.2 = 3:
_$ (/ 0.6 0.2)
3.0
_$ (fix (/ 0.6 0.2))
2
O problema ocorre porque os computadores usam o sistema binrio de
representao e, neste sistema, no possvel representar os nmeros 0.6 e 0.2
com um nmero nito de dgitos binrios e, consequentemente, ocorrem erros
de arredondamento. Por este motivo, o resultado da diviso, em vez de ser 3,
2.999999999999999555910790149937, embora o Auto Lisp o apresente como
3.0. No entanto, ao eliminarmos a parte fraccionria com a funo fix, o que
ca apenas o inteiro 2.
Igualmente perturbante o facto de, embora 0.4 7 = 0.7 4 = 2.8, em
Auto Lisp, (
*
0.4 7) ,=(
*
0.7 4): ambas as expresses tm um valor que
escrito pelo Auto Lisp como 2.8 mas h diferentes erros de arrendondamento
cometidos nas duas expresses que tornam os resultados diferentes.
Note-se que, mesmo quando no h erros de arrendondamento nas ope-
raes, a reduzida preciso com que o Auto Lisp escreve os resultados pode
induzir-nos em erro. Por exemplo, embora internamente o Auto Lisp saiba
que (/ 1.000001 10) produz 0.1000001, ele apenas escreve 0.1 como re-
sultado.
Exerccio 3.11.1 Pretende-se criar umlano de escada comn espelhos capaz de vencer
uma determinada altura a em metros. Admitindo que cada degrau tem uma altura do
espelho h e uma largura do cobertor d que vericam a proporo
2h + d = 0.64
dena uma funo que, a partir da altura a vencer e do nmero de espelhos, calcula o
comprimento do lano de escada.
3.12 Smbolos e Avaliao
Vimos que os smbolos avaliam para aquilo a que estiverem associados no mo-
mento da avaliao. Por este motivo, os smbolos so usados para dar nomes
s coisas. O que mais interessante que os smbolos so, eles prprios, coisas!
26
Para percebermos esta caracterstica dos smbolo vamos apresentar uma
funo pr-denida do Auto Lisp que nos permite saber o tipo de uma enti-
dade qualquer: type. Consideremos a seguinte interaco:
_$ (type 1)
INT
_$ (type "Bom dia!")
STR
_$ (type pi)
REAL
_$ (type quadrado)
USUBR
_$ (type +)
SUBR
Como podemos ver, a funo type devolve-nos o tipo do seu argumento:
INT para inteiros, STR para strings, REAL para reais, etc.
Mas o que so estes resultadosINT, STR, REAL, etc que foram devolvi-
dos pela funo type? Que tipo de objectos so? Para responder questo, o
melhor usar a mesmssima funo type:
_$ (type pi)
REAL
_$ (type (type pi))
SYM
SYM a abreviatura de symbol, indicando que o objecto que devolvido
pela funo type um smbolo. Note-se que, contrariamente ao que acon-
tece com o smbolo pi que est associado ao nmero 3.141519 . . . , os smbolos
REAL, INT, STR, etc., no esto associados a nada, eles apenas so usados
como representao do nome de um determinado tipo de dados.
Se os valores devolvidos pela funo type so objectos do tipo smbolo,
ento dever ser possvel design-los, tal como designamos os nmeros ou as
strings. Mas qual ser o modo de o fazermos? Uma hiptese (errada) seria
escrev-lo tal como escrevemos nmeros ou strings. Acontece que isto pos-
svel no caso dos nmeros e strings pois eles avaliam para eles prprios. J no
caso dos smbolos, sabemos que no avaliam para eles prprios, antes avali-
ando para as entidades a que esto associados naquele momento. Assim, se
quisermos designar o smbolo pi, no bastar escrev-lo numa expresso pois
o que ir resultar aps a sua avaliao no ser um smbolo mas sim o nmero
3.141519 . . . que o valor desse smbolo.
Para ultrapassar este problema precisamos de, por momentos, alterar a se-
mntica habitual que o Lisp atribui aos smbolos. Essa semntica, recordemo-
nos, a de que o valor de um smbolo a entidade a que esse smbolo est
associado nesse momento e esse valor surge sempre que o Lisp avalia o sm-
bolo. Para alterarmos essa semntica, precisamos de indicar ao Lisp que no
queremos que ele avalie um determinado smbolo, i.e., queremos que ele trate
o smbolo como ele , sem o avaliar. Para isso, o Lisp disponibiliza a forma
27
quote. Esta forma, que recebe um nico argumento, tem uma semntica sim-
plicssima: devolve o argumento sem este ter sido avaliado. Reparemos na
seguinte interaco:
_$ pi
3.14159
_$ (quote pi)
PI
_$ (+ 1 2 3)
6
_$ (quote (+ 1 2 3))
(+ 1 2 3)
Como se v, qualquer que seja o argumento da expresso (quote ), o
valor da expresso o prprio sem ter sido avaliado.
A razo de ser do quote est associada distino que existe entre as
frases Diz-me o teu nome e Diz-me o teu nome . No primeiro caso a
frase tem de ser completamente interpretada para que o ouvinte possa dizer
qual o seu prprio nome. No segundo caso, as plicas esto l para indicar ao
ouvinte que ele no deve interpretar o que est entre plicas e deve limitar-se a
dizer a frase o teu nome. As plicas servem, pois, para distinguir o que deve
ser tomado como e o que deve ser interpretado.
Para simplicar a escrita de formas que empregam o quote, o Lisp dispo-
nibiliza uma abreviatura que tem exactamente o mesmo signicado: a plica
(). Quando o Lisp est a fazer a leitura de uma expresso e encontra algo da
forma , aquilo que lido , na realidade, (quote ). Assim, temos:
_$ pi
PI
_$ (+ 1 2 3)
(+ 1 2 3)
Exerccio 3.12.1 Qual o signicado da expresso pi?
28
Funo Argumentos Resultado
+ Vrios nme-
ros
A adio de todos os argumentos. Sem argu-
mentos, devolve zero.
- Vrios nme-
ros
Com apenas um argumento, o seu simtrico.
Com mais de um argumento, a subtraco ao
primeiro argumento de todos os restantes. Sem
argumentos, zero.
*
Vrios nme-
ros
A multiplicao de todos os argumentos. Sem
argumentos, zero.
6
/ Vrios nme-
ros
A diviso do primeiro argumento por todos os
restantes. Sem argumentos, devolve zero.
7
1+ Um nmero A soma do argumento com um.
1- Um nmero A substraco do argumento com um.
abs Um nmero O valor absoluto do argumento.
sin Um nmero
(em radianos)
O seno do argumento .
cos Um nmero
(em radianos)
O cosseno do argumento.
atan Um ou dois
nmeros
Com um argumento, o arco tangente do argu-
mento (em radianos). Com dois argumentos, o
arco tangente da diviso do primeiro pelo se-
gundo (em radianos). O sinal dos argumentos
usado para determinar o quadrante.
sqrt Um nmero
no negativo
A raiz quadrada do argumento.
exp Um nmero A exponencial de base e.
expt Dois nmeros O primeiro argumento elevado ao segundo ar-
gumento.
log Um nmero
positivo
O logaritmo natural do argumento.
max Vrios nme-
ros
O maior dos argumentos.
min Vrios nme-
ros
O menor dos argumentos.
rem Dois ou mais
nmeros
Com dois argumentos, o resto da diviso do pri-
meiro pelo segundo. Com mais argumentos, o
resto da diviso do resultado anterior pelo ar-
gumento seguinte.
fix Um nmero O argumento sem a parte fraccionria.
float Um nmero O argumento convertido em nmero real.
gcd Dois nmeros O maior divisor comum dos dois argumentos.
Tabela 1: Funes matemticas pr-denidas do Auto Lisp.
29
Funo Argumentos Resultado
strcat Vrias strings A concatenao de todos os argumentos. Sem
argumentos, a string vazia .
strlen Vrias strings O nmero de caracteres da concatenao das
strings. Sem argumentos, devolve zero.
strcase Uma string e
um boleano
opcional
Com um argumento ou segundo argumento
nil, a converso para maisculas do argu-
mento, caso contrrio, converso para mins-
culas.
atof Uma string O nmero real cuja representao textual o
argumento.
atoi Uma string O nmero, sem a parte fraccionria, cuja re-
presentao textual o argumento.
itoa Um nmero A representao textual do argumento.
rtos Um, dois ou
trs nmeros
A representao textual do argumento, de
acordo com o modo especicado no segundo
argumento e com a preciso especicada no
terceiro argumento.
Tabela 2: Operaes pr-denidas envolvendo strings.
30

x
Figura 2: Coordenadas rectangulares e polares.
4 Combinao de Dados
Vimos, nas seces anteriores, alguns dos tipos de dados pr-denidos em
Auto Lisp. Em muitos casos, esses tipos de dados so os necessrios e su-
cientes para nos permitir criar os nossos programas mas, noutros casos, ser
necessrio introduzirmos novos tipos de dados. Nesta seco iremos estudar
o modo de o fazermos e iremos exemplic-lo com um tido de dados que nos
ser particularmente til: coordenadas.
4.1 Coordenadas
A Arquitectura pressupe a localizao de elementos no espao. Essa localiza-
o expressa-se em termos do que se designa por coordenadas: as coordenadas
de um ponto identicam univocamente esse ponto no espao.
Se o espao for bi-dimensional (abreviadamente, 2D), cada ponto identi-
cado por duas coordenadas. Se o espao for tri-dimensional (3D), cada ponto
identicado por trs coordenadas. Por agora, vamos considerar apenas o caso
de coordenadas bi-dimensionais.
Existem vrios sistemas de coordenadas bi-dimensionais possveis mas os
mais usais so o sistema de coordenadas rectangulares e o sistemas de coor-
denadas polares, representados na Figura 2. No sistema de coordenadas rec-
tangulares, esse par de nmeros designa a abcissa x e a ordenada y. No sistema
de coordenadas polares, esse par de nmeros designa o raio vector e o ngulo
polar . Em qualquer caso, as coordenadas bi-dimensionais so descritas por
um par de nmeros.
Como vimos nas seces anteriores, o Auto Lisp sabe lidar com o conceito
de nmeros. Vamos agora ver que ele tambm sabe lidar com o conceito de
par.
4.2 Pares
Em Lisp, podemos criar pares atravs da funo pr-denida cons. Esta fun-
o, cujo nome a abreviatura da palavra construct, aceita quaisquer duas en-
tidades como argumentos e produz um par com essas duas entidades. Tradi-
31
cionalmente, usual dizer que o par um cons.
12
Eis um exemplo da criao de um par de nmeros:
_$ (cons 1 2)
(1 . 2)
Como podemos ver pela interaco anterior, quando o Lisp pretende es-
crever o resultado da criao de um par, ele comea por escrever um abrir pa-
rnteses, depois escreve o primeiro elemento do par, depois escreve um ponto
de separarao, depois escreve o segundo elemento do par e, nalmente, es-
creve um fechar parnteses. Esta notao denomina-se par com ponto ou,
no original, dotted pair.
Quando o Lisp cria um par de elementos, cria uma associao interna en-
tre esses elementos que podemos representar gracamente como uma caixa
dividida em duas metades, cada uma apontando para um dos elementos. Por
exemplo, o par anterior pode ser representado gracamente da seguinte forma:
1 2
A representao grca anterior denomina-se notao de caixa e pon-
teiro precisamente porque mostra os pares como caixas com ponteiros para
os elementos dos pares.
Uma vez que a construo de um par feita usando uma funo, a sua
invocao segue as mesmas regras de avaliao de todas as outras invocaes
de funes, ou seja, as expresses que constituem os argumentos so avaliadas
e so os resultados dessas avaliaes que so usados como elementos do par.
Assim, temos:
_$ (cons (+ 1 2) (
*
3 4))
(3 . 12)
_$ (cons 1 "dois")
(1 . "dois")
_$ (cons (area-circulo 10) (area-triangulo 20 30))
(314.159 . 300)
A propsito deste ltimo exemplo, note-se a diferena entre o ponto rela-
tivo parte fraccionria do primeiro nmero e o ponto relativo separao
dos elementos do par. Na primeira ocorrncia, o ponto faz parte da sintaxe do
nmero fraccionrio e no pode ter espaos. Na segunda ocorrncia, o ponto
faz parte da sintaxe dos pares e tem de ter espaos.
A partir do momento em que temos um par de entidades, podemos estar
interessados em saber quais so os elementos do par. Em Lisp, dado um par
de entidades (um cons) podemos obter o primeiro elemento do par usando
a funo car e o segundo usando a funo cdr.
12
O cons para o Lisp o mesmo que as tabelas (arrays) e estruturas (records, structs) so para
as outras linguagens como Pascal ou C. Na prtica, o cons um mecanismo de agregao de
entidades.
32
_$ (car (cons 1 2))
1
_$ (cdr (cons 1 2))
2
Note-se que aplicar o car ou o cdr a um cons no afecta esse cons, ape-
nas diz qual o primeiro ou segundo elemento do cons. Em termos da re-
presentao grca de caixa e ponteiro, a aplicao das funes car e cdr
corresponde, simplesmente, a seguir os apontadores da esquerda e direita, res-
pectivamente.
Os nomes car e cdr tm raizes histricas e, embora possa no parecer, so
relativamente fceis de decorar. Uma mnemnica que pode ajudar pensar
que o cAr obtm o elemento que vem Antes e o cDr obtm o elemento
que vem Depois.
Uma vez que a funo cons forma pares com os seus argumentos, igual-
mente possvel formar pares de pares. Os seguintes exerccios exemplicam
esta situao.
Exerccio 4.2.1 Qual o signicado da expresso (cons (cons 1 2) 3)?
Exerccio 4.2.2 Qual o signicado da expresso (car (cons (cons 1 2) 3))?
Exerccio 4.2.3 Qual o signicado da expresso (cdr (cons (cons 1 2) 3))?
4.3 Operaes com Coordenadas
A partir do momento em que sabemos construir pares, podemos criar coor-
denadas e podemos denir operaes sobre essas coordenadas. Para criarmos
coordenadas podemos simplesmente juntar num par os dois nmeros que re-
presentam a abcissa e a ordenada. Por exemplo, o ponto do espao cartesiano
(1, 2) pode ser construdo atravs de:
_$ (cons 1 2)
(1 . 2)
Uma vez que estamos a fazer um par que contm, primeiro, a abcissa e,
depois, a ordenada, podemos obter estes valores usando, respectivamente, as
funes car e cdr.
Para melhor percebermos a utilizao destas funes, imaginemos que pre-
tendemos denir uma operao que mede a distncia d entre os pontos P
0
=
(x
0
, y
0
) e P
1
= (x
1
, y
1
) que podemos ver na Figura 3. A distncia d corres-
ponde, logicamente, ao comprimento da recta que une P
0
a P
1
.
A aplicao do teorema de Pitgoras permite-nos determinar a distncia d
em termos das coordenadas dos pontos P
0
a P
1
:
d =

(x
1
x
0
)
2
+ (y
1
y
0
)
2
A traduo desta frmula para Auto Lisp consiste da seguinte denio:
33
P
0
P
1
d
x
0
y
0
x
1
y
1
Figura 3: Distncia entre dois pontos.
(defun distancia-2d (p0 p1)
(sqrt (+ (quadrado (- (car p1) (car p0)))
(quadrado (- (cdr p1) (cdr p0))))))
Podemos agora experimentar a funo com um caso concreto:
_$ (distancia-2d (cons 2 3) (cons 8 6))
6.7082
4.4 Abstraco de Dados
Embora tenhamos pensado na operao distancia-2d como uma funo
que recebe as coordenadas de dois pontos, quer quando observamos a deni-
o da funo, quer quando observamos a sua utilizao subsequente, o que
vemos a invocao das operaes cons, car e cdr e, consequentemente, no
nos nada evidente que a funo esteja a lidar com coordenadas. Na verdade,
o conceito de coordenadas apenas existe na nossa cabea e a realidade que
estamos a construir e manipular coordenadas directamente atravs de pares.
Esta diferena entre os conceitos que temos na nossa cabea e os que empre-
gamos na programao torna-se ainda mais evidente quando pensamos nou-
tras entidades matemticas que, tal como as coordenadas, tambm agrupam
elementos mais simples. Um nmero racional, por exemplo, dene-se como
um par de dois nmeros inteiros, o numerador e o denominador. semelhana
do que zmos com as coordenadas, tambm poderiamos criar um nmero
racional em Auto Lisp custa da funo cons e poderiamos seleccionar o nu-
merador e o denominador custa das funes car e cdr. Outro exemplo ser
a implementao de nmeros complexos. Estes tambm so constitudos por
pares de nmeros reais e tambm poderiam ser implementados custa das
mesma funes cons, car e cdr.
medida que formos implementando em Auto Lisp as funes que ma-
nipulam estes conceitos, a utilizao sistemtica das funes cons, car e cdr
far com que seja cada vez mais difcil perceber qual ou quais os tipo de da-
dos a que se destina uma determinada funo. De facto, a partir apenas das
34
funes cons, car e cdr no podemos saber se estamos a lidar com coorde-
nadas, racionais, complexos ou qualquer outro tipo de dados que tenhamos
implementado em termos de pares.
Para resolvermos este problema necessrio preservarmos no Auto Lisp o
conceito original que pretendemos implementar. Para isso, temos de abstrair
a utilizao que fazemos dos pares, escondendo-a no interior de funes
que representem explicitamente os conceitos originais. Vamos agora exempli-
car esta abordagem reconsiderando o conceito de coordenadas cartesianas
bi-dimensionais e introduzindo funes apropriadas para esconder a utiliza-
o dos pares.
Assim, para construirmos as coordenadas (x, y) a partir dos seus compo-
nentes x e y, ao invs de usarmos directamente a funo cons vamos denir
uma nova funo que vamos denominar de xy:
13
(defun xy (x y)
(cons x y))
A construo de coordenadas bi-dimensionais por intermdio da funo
xy apenas o primeiro passo para abstrairmos a utilizao dos pares. O se-
gundo passo a criao de funes que acedem abcissa x e ordenada y das
coordenadas (x, y). Para isso, vamos denir, respectivamente, as funes cx e
cy como abreviaturas de coordenada x e coordenada y:
14
(defun cx (c)
(car c))
(defun cy (c)
(cdr c))
As funes xy, cx e cy constituem uma abstraco das coordenadas bi-
dimensionais que nos permitem escrever as funes que manipulam coorde-
nadas sem termos de pensar na sua implementao em termos de pares. Esse
facto torna-se evidente quando reescrevemos a funo distancia-2d emter-
mos destas novas funes:
(defun distancia-2d (p0 p1)
(sqrt (+ (quadrado (- (cx p1) (cx p0)))
(quadrado (- (cy p1) (cy p0))))))
Reparemos que, contrariamente ao que acontecia com a primeira verso
desta funo, a leitura da funo d agora uma ideia clara do que ela faz. Ao
13
Naturalmente, podemos considerar outro nome igualmente apropriado como, por exem-
plo, coordenadas-cartesianas-2d. Contudo, como de esperar que tenhamos frequente-
mente de criar coordenadas, conveniente que adoptemos um nome sucientemente curto e,
por isso, vamos adoptar o nome xy.
14
Tal como a funo xy poderia ter um nome mais explcito, tambm as funes que acedem
abcissa e ordenada se poderiam denominar abcissa e ordenada ou coordenada-x e
coordenada-y ou qualquer outro par de nomes sucientemente claro. No entanto, sendo as
coordenadas um tipo de dados com muito uso, mais uma vez se tornar vantajoso que empre-
guemos nomes curtos.
35
P

x
P

Figura 4: Deslocamento de um ponto.


invs de termos de pensar em termos de car e cdr, vemos que a funo lida
com as coordenadas x e y. A utilizao da funo tambm mostra claramente
que o que ela est a manipular so coordenadas:
_$ (distancia-2d (xy 2 3) (xy 8 6))
6.7082
A introduo das operaes de coordenadas xy, cx e cy no s torna mais
claro o signicado dos nossos programas como facilita bastante a denio de
novas funes. Agora, ao invs de termos de nos lembrar que as coordena-
das so pares cujo primeiro elemento a abcissa e cujo segundo elemento
a ordenada, basta-nos pensar nas operaes bsicas de coordenadas e denir
as funes que pretendermos em termos delas. Por exemplo, imaginemos que
pretendemos denir uma operao que faz deslocar um ponto de uma de-
terminada distncia, expressa em termos de um comprimento
x
e de uma
altura
y
, tal como est apresentado na Figura 4. Como ser evidente pela Fi-
gura, sendo P = (x, y), ento teremos P

= (x +
x
, y +
y
). Para simplicar
o uso desta funo, vamos denomin-la de +xy. Naturalmente, ela precisa de
receber, como parmetros, o ponto de partida P e os incrementos
x
e
y
que
iremos denominar de x e y, respectivamente.
A denio da funo ca ento:
(defun +xy (p x y)
(xy (+ (cx p) x)
(+ (cy p) y)))
Uma vez que esta funo recebe coordenadas como argumento e produz
coordenadas como resultado, ela constitui outra importante adio ao con-
junto de operaes disponveis para lidar com coordenadas. Naturalmente,
podemos usar a funo +xy para denir novas funes como, por exemplo, os
casos particulares de deslocamento horizontal e vertical que se seguem:
(defun +x (p dx)
(+xy p dx 0))
36
y
z
x
P
x
z
y
Figura 5: Coordenadas Cartesianas
(defun +y (p dy)
(+xy p 0 dy))
4.5 Coordenadas Tri-Dimensionais
As coordenadas bi-dimensionais localizam pontos num plano. A localizao
de pontos no espao requer coordenadas tri-dimensionais. Tal como aconte-
cia com as coordenadas bi-dimensionais, tambm existem vrios sistemas de
coordenadas tri-dimensionais, nomeadamente, o sistema de coordenadas rec-
tangulares, o sistema de coordenadas cilndricas e o sistema de coordenadas
esfricas. Em qualquer deles, a localizao de um ponto no espao feita
custa de trs parmetros independentes. As coordenadas tri-dimensionais so,
por isso, triplos de nmeros.
Nesta seco vemos debruar-nos apenas sobre o sistema de coordenadas
rectangulares, tambm conhecidas por coordenadas Cartesianas em honra ao seu
inventor: Ren Descartes. Estas coordenadas esto representadas na Figura 5.
Como vimos na seco anterior, o Auto Lisp disponibiliza a operao cons
para permitir formar pares de elementos, o que nos permitiu traduzir as coor-
denadas bi-dimensionais da geometria para pares de nmeros em Auto Lisp.
Agora, a situao ligeiramente mais complexa pois o Auto Lisp no disponi-
biliza nenhuma operao capaz de fazer triplos de nmeros. Ou qudruplos.
Ou quntuplos. Ou, na verdade, qualquer outro tipo de tuplo para alm dos
duplos.
Na realidade, esta aparente limitao do Auto Lisp perfeitamente justi-
cada pois trivial, a partir de pares, formarmos qualquer tipo de agrupamento
que pretendamos. Um triplo pode ser feito custa de dois pares: um contendo
dois elementos e outro contendo este par e o terceiro elemento. Um qudruplo
pode ser feito custa de trs pares: um par para cada dois elementos e um
terceiro par contendo os dois pares anteriores. Um quntuplo pode ser feito
custa de quatro pares: trs pares para formar um qudruplo e um quarto par
37
para juntar o qudruplo ao quinto elemento. Agrupamentos com maior n-
mero de elementos podem ser formados simplesmente seguindo esta lgica.
De acordo comesta abordagem, para criarmos coordenadas tri-dimensionais
temos de usar dois pares. Para abstrair a utilizao destes pares, vamos de-
nir a funo xyz para construir coordenadas tri-dimensionais e vamos denir
as funes cx, cy e cz para aceder coordenada x, y e z, respectivamente.
Comecemos pela funo xyz:
(defun xyz (x y z)
(cons (cons x y) z))
Reparemos que a funo produz o triplo fazendo um par com os dois
primeiros elementos x e y e, em seguida, fazendo um par com o par anterior e
com o terceiro elemento z. Em notao de caixa e ponteiro este agrupamento
de elementos tem a seguinte forma:
x
y
z
Como evidente, qualquer outro arranjo de pares que juntasse os trs ele-
mentos seria igualmente vlido.
A partir do momento em que temos a funo xyz que constri as coorde-
nadas, estamos em condies de denir as funes que acedem s suas com-
ponentes:
(defun cx (c)
(car (car c)))
(defun cy (c)
(cdr (car c)))
(defun cz (c)
(cdr c))
Notemos que as funes que seleccionamos componentes das coordenadas
tm de ser consistentes com os pares construdos pela funo xyz. Uma vez
que a coordenada x o elemento da esquerda do par que o elemento da
esquerda do par que contm os componentes das coordenadas, precisamos de
empregar duas vezes a funo car na denio da funo cx. Do mesmo
modo, a coordenada y o elemento da direita do par que o elemento da
esquerda, pelo que temos primeiro de aplicar a funo car para aceder ao par
que contm x e y e temos de lhe aplicar a funo cdr para aceder a y.
As duas ltimas combinaes podem ser feita de forma abreviada usando
as funes pr-denidas caar e cdar:
38
_$ (caar (cons (cons 1 2) 3))
1
_$ (cdar (cons (cons 1 2) 3))
2
Repare-se que a sequncia de letras a e d entre as letras c e r indica a com-
posio de funes em questo. Assim, a funo cadr signica o car do cdr
do argumento, i.e., (cadr c)=(car (cdr c)); e a funo caar signica o
car do car do argumento, i.e., (caar c)=(car (car c)). Por tradio, o
Auto Lisp dene todas as possveis combinaes de at quatro invocaes das
funes car e cdr. Assim, para alm das funes caar, cadr, cdar e cddr
que correspondem a todas as possveis invocaes de duas funes, existem
ainda as variaes de trs invocaes caaar, caadr, cadar, etc., e as vari-
aes de quatro invocaes caaaar, caaadr, caadar, caaddr, etc. No en-
tanto, deve-se evitar a utilizao destas combinaes de funes como cadar,
cdadar, cdar e, por vezes, at mesmo as car e cdr, pois tornam o cdigo
pouco claro. Para termos um pouco mais de clareza devemos denir funes
cujo nome seja sucientemente explicativo do que a funo faz.
A partir do momento em que temos coordenadas tri-dimensionais pode-
mos denir operaes que lidem com elas. Uma funo til a que mede a
distncia entre dois pontos no espao tri-dimensional. Ela corresponde a uma
generalizao trivial da funo distancia-2d onde necessrio ter emconta
a coordenada z dos dois pontos. Num espao tri-dimensional, a distncia d en-
tre os pontos P
0
= (x
0
, y
0
, z
0
) e P
1
= (x
1
, y
1
, z
1
) dada por
d =

(x
1
x
0
)
2
+ (y
1
y
0
)
2
+ (z
1
z
0
)
2
Traduzindo est denio para Auto Lisp, temos:
(defun distancia-3d (p0 p1)
(sqrt (+ (quadrado (- (cx p1) (cx p0)))
(quadrado (- (cy p1) (cy p0)))
(quadrado (- (cz p1) (cz p0))))))
semelhana do que zemos para as coordenadas bi-dimensionais, tam-
bmpodemos denir operadores para incrementar as coordenadas tri-dimensionais
de umponto de uma determinada distncia especicada emtermos das pro-
jeces x, y e z:
(defun +xyz (p x y z)
(xyz (+ (cx p) x)
(+ (cy p) y)
(+ (cz p) z)))
Tal como acontecia com a funo +xy, tambm a funo +xyz indepen-
dente do arranjo particular de pares que usemos para implementar as coor-
denadas tri-dimensionais. Desde que mantenhamos a consistncia entre as
funes cx, cy e cz, que seleccionam os componentes das coordenadas tri-
dimensionais, e a funo xyz que cria coordenadas tri-dimensionais a partir
dos seus componentes, podemos livremente empregar outros arranjos de pa-
res.
39
Exerccio 4.5.1 Dena a funo +z que, dado umponto emcoordenadas tri-dimensionais,
calcula as coordenadas do ponto que lhe est directamente por cima distncia z.
4.6 Coordenadas Bi- e Tri-Dimensionais
Embora tenhamos conseguido implementar quer coordenadas bi-dimensionais,
quer coordenadas tri-dimensionais, as suas implementaes em termos de pa-
res so intrinsecamente incompatveis. Este problema claramente visvel, por
exemplo, na implementao da operao que selecciona a coordenada x que,
na verso para coordenadas bi-dimensionais, tem a forma
(defun cx (c)
(car c))
e, na verso para coordenadas tri-dimensionais, tem a forma
(defun cx (c)
(car (car c)))
Obviamente, no possvel termos duas funes diferentes com o mesmo
nome, pelo que temos de escolher qual das verses pretendemos usar e, por
arrastamento, qual o nmero de dimenses que pretendemos usar.
Acontece que, do ponto de vista matemtico, as coordenadas bi-dimensionais
so apenas um caso particular das coordenadas tri-dimensionais e, portanto,
seria desejvel podermos ter uma nica operao cx capaz de obter a co-
ordenada x quer de coordenadas bi-dimensionais, quer de coordenadas tri-
dimensionais. Logicamente, o mesmo podemos dizer da operao cy.
Para isso, necessrio repensarmos a forma como implementamos as co-
ordenadas em termos de pares, de modo a encontrarmos um arranjo de pares
que seja utilizvel por ambos os tipos de coordenadas. Para simplicar, po-
demos comear por considerar que, semelhana do que zmos para o caso
bi-dimensional, usamos um primeiro par para conter a coordenada x, tal como
se apresenta em seguida:
x
?
Falta agora incluirmos a coordenada y no caso bi-dimensional e as coor-
denadas y e z no caso tri-dimensional. Se o objectivo termos um arranjo de
pares que funcione para os dois casos, ento crucial que a coordenada y -
que armazenada de forma idntica em ambos. Uma vez que as coordenadas
tri-dimensionais exigem pelo menos mais um par, podemos arbitrar a seguinte
soluo:
x
y
?
40
Embora no caso bi-dimensional no seja preciso armazenar mais nada, um
par sempre composto por dois elementos, pelo que temos de decidir o que
guardar no lugar assinalado com ?. Uma vez que, para coordenadas bi-
dimensionais, no h nada para guardar nesse lugar, podemos empregar um
elemento qualquer que signique o nada, o vazio. A linguagem Lisp dispo-
nibiliza a constante nil precisamente para esse m. O nome nil uma con-
traco da palavra nihil que, em latim, signica o vazio.
Empregando a constante nil, as coordenadas bi-dimensionais (x, y) pas-
sam a ter a seguinte implementao:
x
y
nil
Para construir a estrutura anterior, a funo xy passa a ter a seguinte de-
nio:
(defun xy (x y)
(cons x (cons y nil)))
No caso das coordenadas tri-dimensionais, poderamos substituir o ?
pelo valor da coordenada z mas, tal como considermos as coordenadas bi-
dimensionais como umcaso particular das coordenadas tri-dimensionais, tam-
bm as coordenadas tri-dimensionais podem ser vistas como um caso particu-
lar das coordenadas tetra-dimensionais e assim sucessivamente.
15
Isto sugere
que devemos repetir a mesma estrutura medida que vamos aumentando o
nmero de dimenses. Assim, para as coordenadas tri-dimensionais (x, y, z),
podemos conceber a seguinte organizao:
x
y
z
nil
Obviamente, precisamos de redenir a funo xyz:
(defun xyz (x y z)
(cons x (cons y (cons z nil))))
15
Embora, do ponto de vista da Arquitectura clssica, no seja necessrio trabalhar com mais
do que trs coordenadas, as modernas ferramentas de visualizao podem necessitar de traba-
lhar com coordenadas tetra-dimensionais, por exemplo, para lidarem com o tempo.
41
fcil constatarmos que a duas estruturas anteriores so perfeitamente
compatveis no sentido de podermos ter uma s verso das operaes cx e cy
que funcione quer para coordenadas bi-dimensionais, quer para coordenadas
tri-dimensionais. De acordo com a notao de caixa e ponteiro apresentada,
podemos denir:
(defun cx (c)
(car c))
(defun cy (c)
(car (cdr c)))
(defun cz (c)
(car (cdr (cdr c))))
importante referirmos que esta redenio das funes no perturba as
funes j denidas +xy, distancia-2d e distancia-3d. De facto, desde
que se mantenha a consistncia entre as funes que constriem as coordena-
das e as que seleccionam os seus componentes, nada ser afectado.
4.7 A Notao de Lista
O arranjo de pares que adoptmos para implementar coordenadas no origi-
nal, sendo usado desde a inveno da linguagem Lisp para implementar agru-
pamentos com um nmero arbitrrio de elementos. A esses agrupamentos
d-se o nome de listas. As listas so um tipo de dados muito utilizado na lin-
guagem Lisp e o nome Lisp , na verdade, um acrnimo de List Processing.
De forma a tornar o uso de listas mais simples, o Lisp no s disponibiliza
um conjunto de operaes especicamente destinadas a lidar com listas como
imprime as listas de forma especial: quando o segundo elemento de um par
outro par, o Lisp escreve o resultado sob a forma de uma lista de elementos:
_$ (cons 1 (cons 2 (cons 3 nil)))
(1 2 3)
Repare-se, no exemplo anterior, que os pares foram escritos usando uma
notao diferente que evita o ponto necessrio para representar os dotted pairs
e evita tambm escrever a constante nil. Esta notao intencionalmente
usada pelo Lisp para facilitar a leitura de listas pois, quando se pensa numa
lista como uma sequncia de elementos prefervel ver esses elementos dis-
postos em sequncia a v-los como um aglomerado de pares. Contudo, con-
vmno esquecermos que, internamente, a lista de facto implementada usando
um aglomerado de pares.
Dada uma lista de elementos, qual o signicado de lhe aplicar as operaes
car e cdr? Para responder a esta pergunta podemos simplesmente experi-
mentar:
_$ (car (cons 1 (cons 2 (cons 3 nil))))
1
_$ (cdr (cons 1 (cons 2 (cons 3 nil))))
(2 3)
42
Note-se que a funo car obteve o primeiro elemento da lista enquanto
que a funo cdr obteve os restantes elementos da lista, i.e., a lista a partir
(inclusive) do segundo elemento. Isto sugere que podemos ver uma lista como
sendo composta por um primeiro elemento seguido do resto da lista. Segundo
este raciocnio, depois de termos obtido o ltimo elemento da lista, o resto
da lista dever ser uma lista vazia, i.e., uma lista sem quaisquer elementos.
Para testarmos esta ideia podemos aplicar sucessivamente a funo cdr a uma
dada lista:
_$ (cons 1 (cons 2 (cons 3 nil)))
(1 2 3)
_$ (cdr (cons 1 (cons 2 (cons 3 nil))))
(2 3)
_$ (cdr (cdr (cons 1 (cons 2 (cons 3 nil)))))
(3)
_$ (cdr (cdr (cdr (cons 1 (cons 2 (cons 3 nil))))))
nil
Reparemos que, medida que fomos aplicando sucessivamente a funo
cdr, a lista foi encolhendo, i.e., fomos acedendo a partes sucessivamente
mais pequenas da lista. No limite, quando aplicmos o cdr lista (3) que
j s tinha um elemento, estaramos espera de obter a lista vazia (), i.e, a
lista sem quaisquer elementos mas, no seu lugar, obtivmos nil. Tal deve-
se ao facto de as listas do Lisp serem apenas um artifcio de visualizao
sobre um arranjo particular de pares e, na realidade, a operao cdr continua
a fazer o que sempre fez: acede ao segundo elemento do par que, no caso de
uma lista com um s elemento apenas a constante nil. Por este motivo, para
alm de representar o vazio, usual considerar que a constante nil tambm
representa a lista vazia.
Tal como as funes car e cdr podem ser vistas como operaes sobre
listas, tambm a funo cons o pode ser. Reparemos na seguinte interaco:
_$ (cons 1 nil)
(1)
_$ (cons 1 (cons 2 nil))
(1 2)
_$ (cons 1 (cons 2 (cons 3 nil)))
(1 2 3)
Como podemos ver, quando o segundo argumento de umcons uma lista
(vazia ou no), o resultado visto como a lista que resulta de juntar o primeiro
argumento do cons no incio daquela lista.
Para simplicar a criao de listas, o Lisp disponibiliza uma funo que
recebe qualquer nmero de argumentos e que constroi uma sequncia de pares
com os sucessivos argumentos de forma a constituirem uma lista:
_$ (list 1 2 3 4)
(1 2 3 4)
_$ (list 1 2)
(1 2)
43
_$ (list 1)
(1)
Como evidente, uma expresso da forma (list e
1
e
2
... e
n
) abso-
lutamente idntica a (cons e
1
(cons e
2
(... (cons e
n
nil) ...))).
Obviamente, quando recebe zero argumentos a funo list produz uma
lista vazia:
_$ (list)
nil
Exerccio 4.7.1 Qual o signicado da expresso (list (list))?
Exerccio 4.7.2 Quantos elementos tema lista resultante de (list (list (list)))?
Exerccio 4.7.3 Qual o signicado da expresso (cons (list 1 2) (list 3 4))?
4.8 tomos
Vimos que os pares (e as listas) permitem-nos criar aglomeraes de elementos
e que podemos posteriormente aceder aos componentes dessas aglomeraes
usando as operaes car e cdr. De facto, atravs de combinaes de cars e
cdrs conseguimos aceder a qualquer elemento que faa parte da aglomerao.
O que no possvel, contudo, usar car ou cdr para aceder ao interior
de um desses elementos. Por exemplo, no possvel, usando as operaes
car ou cdr, aceder a um carcter qualquer dentro de uma string. Por este
motivo, as strings dizem-se atmicas, i.e., no decomponveis. Os nmeros,
obviamente, tambm so atmicos.
Sendo uma lista uma aglomerao de elementos, natural pensar que uma
lista no atmica. Contudo, h uma lista em particular que merece um pouco
mais de ateno: a lista vazia. Uma lista vazia no decomponvel pois, de
facto no contm nenhum elemento que se possa obter usando o car nem
nenhuns restantes elementos que se possam obter usando o cdr.
16
Se no se
pode usar nem o car nem o cdr, isso sugere que a lista vazia , na realidade,
um tomo e, de facto, o Auto Lisp assim o considera.
O facto de a lista vazia ser, simultaneamente, um tomo e uma lista pro-
voca um aparente paradoxo na denio de atomicidade pois faz com que
exista uma listaa lista vaziaque aparenta ser simultaneamente atmica e
no atmica. No entanto, o parodoxo apenas aparente pois, na realidade, a
denio de atomicidade apenas exclui pares. Uma vez que a lista vazia no
um par, ela atmica, embora seja uma lista.
17
Exerccio 4.8.1 Classique, quanto atomicidade, o resultado da avaliao das se-
guintes expresses:
16
Na realidade, alguns dialectos de Lisp, incluindo o Auto Lisp, consideram que possvel
aplicar as funes car e cdr lista vazia, obtendo-se, em ambos os casos, a lista vazia.
17
Nesta matria, a documentao do Auto Lisp est simplesmente incorrecta pois arma que
tudo o que no for uma lista um tomo, esquecendo-se de excluir a lista vazia que, obvia-
mente, uma lista mas tambm um tomo.
44
1. (cons 1 2)
2. (list 1 2)
3. (strcat "Bom" " " "Dia")
4. nil
5. (+ 1 2 3)
6. (list 1)
7. (list)
8. (car (cons 1 (cons 2 nil)))
9. (cdr (cons 1 (cons 2 nil)))
4.9 Tipos Abstractos
A utilizao das operaes xyz, cx, cy e cz permite-nos denir um novo tipo
de dadosas coordenadas cartesianas tri-dimensionaise, mais importante,
permite-nos abstrair a implementao desse tipo de dados, i.e., esquecer o ar-
ranjo particular de pares que o implementa. Por este motivo, denomina-se este
novo tipo de dados por tipo abstracto. Ele abstracto porque apenas existe no
nosso pensamento. Para o Lisp, como vimos, as coordenadas so apenas ar-
ranjos particulares de pares. Esse arranjo particular denomina-se representao
dos elementos do tipo e, como vimos quando mudmos de um particular ar-
ranjo de pares para outro, possvel mudarmos a representao de um tipo
abstracto sem afectar os programas que usam o tipo abstracto.
Umtipo abstracto caracterizado apenas pelas suas operaes e estas dividem-
se em dois conjuntos fundamentais: os construtores que, a partir de argumen-
tos de tipos apropriados, produzem elementos do tipo abstracto, e os selecto-
res que, a partir de um elemento do tipo abstracto, produzem os seus consti-
tuintes. Existem ainda outras categorias de operaes mas, por agora iremos
concentrarmo-nos apenas nestas duas.
No caso das coordenadas cartesianas tri-dimensionais, o conjunto dos cons-
trutores apenas contm a funo xyz, enquanto que o conjunto dos selectores
contm as funes cx, cy e cz. Para um tipo abstracto, a relao entre os
construtores e os selectores crucial pois eles tm de ser consistentes entre
si. Matematicamente, essa consistncia assegurada por equaes que, no caso
presente, se podem escrever da seguinte forma:
(cx (xyz x y z)) = x
(cy (xyz x y z)) = y
(cz (xyz x y z)) = z
Se modicarmos a representao de coordenadas mas mantivermos a con-
sistncia entre os construtores e os selectores, manter-se- tambm o correcto
funcionamento do tipo abstracto. Foi por este motivo que nos foi possvel re-
fazer a implementao das coordenadas bi- e tri-dimensionais sem afectar as
funes j denidas +xy, distancia-2d e distancia-3d.
45
Exerccio 4.9.1 O que um construtor de um tipo abstracto?
Exerccio 4.9.2 O que um selector de um tipo abstracto?
Exerccio 4.9.3 O que a representao de um tipo abstracto?
Exerccio 4.9.4 Dado um ponto P
0
= (x
0
, y
0
) e uma recta denida por dois pontos
P
1
= (x
1
, y
1
) e P
2
= (x
2
, y
2
), a distncia mnima d do ponto P
0
recta obtm-se pela
frmula:
d =
[(x
2
x
1
)(y
1
y
0
) (x
1
x
0
)(y
2
y
1
)[

(x
2
x
1
)
2
+ (y
2
y
1
)
2
Dena uma funo denominada distancia-ponto-recta que, dadas as coorde-
nadas dos pontos P
0
, P
1
e P
2
, devolve a distncia mnima de P
0
recta denida por
P
1
e P
2
.
4.10 Coordenadas em AutoCad
Como mostrmos nas seces anteriores, a compatibilizao das operaes
que lidamcomcoordenadas bi- e tri-dimensionais levou-nos a escolher represent-
las por intermdio de listas. Para alm de esta representao ser mais sim-
ples de ler, tem ainda outra enorme vantagem: totalmente compatvel com
a forma como as funcionalidades do AutoCad esperam receber coordenadas.
De facto, como iremos ver, o prprio AutoCad necessita que as coordenadas
das entidades geomtricas que pretendemos criar sejam especicadas como
listas de nmeros: dois nmeros no caso das coordenadas bi-dimensionais e
trs nmeros no caso das coordenadas tri-dimensionais.
Seria ento de esperar que j existissem pr-denidas em Auto Lisp as ope-
raes que lidam com coordenadas mas, na realidade, tal no acontece porque,
na altura em que o Auto Lisp foi criado a teoria dos tipos abstractos ainda no
tinha sido efectivamente posta em prtica. Nessa altura, no se tinha a noo
clara das vantagens desta abordagem mas tinha-se uma noo muito clara de
um dos seus problemas: piorava a performance dos programas.
De facto, bvio que, a partir de uma lista representando as coordenadas
de um ponto, mais rpido obter a coordenada x usando a funo car do que
usando o selector cx que, indirectamente, invoca a funo car.
Como, na altura emque a teoria dos tipos abstractos apareceu, os computa-
dores ainda no eram sucientemente rpidos para que os programadores se
pudessem dar ao luxo de desperdiar performance, a penalizao induzida
pela teoria no foi bem aceite durante algum tempo.
18
Quando os computado-
res se tornaram sucientemente rpidos, a situao mudou e os programado-
res passaram a considerar que as vantagens da utilizao de tipos abstractos
ultrapassava largamente a cada vez mais residual desvantagem da perda de
performance. Actualmente, ponto assente que devemos sempre usar tipos
abstractos.
18
Essa penalizao variava de linguagem para linguagem. Nalgumas linguagens, ditas estati-
camente tipicadas, a penalizao poderia ser pequena. Noutras, ditas dinamicamente tipicadas,
a penalizao era geralmente mais elevada. O Lisp insere-se no grupo das linguagens dinami-
camente tipicadas.
46
Infelizmente, o Auto Lisp foi desenvolvido h demasiados anos e no se
encontra to actualizado como seria desejvel. Se zermos uma anlise dos
programas Auto Lisp existentes, incluindo programas desenvolvidos recente-
mente, iremos constatar que a prtica usual a manipulao directa da repre-
sentao dos tipos, saltando por cima de qualquer denio de tipos abstrac-
tos. Em particular, a manipulao de coordenadas feita usando directamente
as operaes do tipo lista, i.e., construindo coordenadas com a funo list
e acedendo aos seus valores com as funes car, cadr e caddr. Acontece
que esta violao do tipo abstracto ocorre, actualmente, muito mais por razes
histricas do que por razes de performance.
Embora sejamos grandes defensores do respeito pragmtica do Auto
Lisp, neste caso particular vamos adoptar uma abordagem diferente: por mo-
tivos de clareza dos programas, de facilidade da sua compreenso e de faci-
lidade da sua correco, vamos empregar as operaes do tipo abstracto co-
ordenadas, nomeadamente xy, cx e cy e vamos evitar, sempre que possvel,
aceder directamente representao das coordenadas, i.e., vamos evitar usar
as funes list, car e cadr para manipular coordenadas. Isso no impede
que usemos essas funes para outros ns, em particular, para manipular lis-
tas. Uma vez que as coordenadas esto implementadas usando listas, esta
distino poder parecer confusa mas, na verdade, no : as coordenadas no
so listas embora a representao das coordenadas seja uma lista.
Naturalmente, quando o leitor consultar programas escritos por outros
programadores de Auto Lisp dever ter em conta estas subtilezas e dever
conseguir perceber se uma dada lista presente num programa signica coor-
denadas ou se signica outro tipo abstracto qualquer.
4.11 Coordenadas Polares
Uma das vantagens da utilizao dos tipos abstractos de informao que
se torna fcil desenvolver novas operaes com base nas operaes do tipo.
Por exemplo, embora o tipo coordenadas bi-dimensionais esteja descrito em
termos de coordenadas rectangulares, nada nos impede de denir operaes para
manipular coordenadas polares.
Tal como representado da Figura 6, uma posio no plano bi-dimensional
descrita pelos nmeros x e ysignicando, respectivamente, a abcissa e a orde-
nadaenquanto que a mesma posio emcoordenadas polares descrita pelos
nmeros e signicando, respectivamente, o raio vector (tambm chamado
mdulo) e o ngulo polar (tambm chamado argumento). Com a ajuda da trigo-
nometria e do teorema de Pitgoras conseguimos facilmente relacionar estas
coordenadas entre si:

x = cos
y = sin

x
2
+ y
2
= arctan
y
x
47

x
Figura 6: Coordenadas rectangulares e polares.
Com base nas equaes anteriores, podemos agora denir a funo pol
(abreviatura de polar) que contri coordenadas a partir da sua representa-
o polar simplesmente convertendo-a para a representao rectangular equi-
valente.
(defun pol (ro fi)
(xy (
*
ro (cos fi))
(
*
ro (sin fi))))
Assim sendo, o tipo abstracto coordenadas polares ca representado em
termos do tipo coordenadas rectangulares. Por este motivo, os selectores do
tipo coordenadas polaresa funo pol-ro que nos permite obter o mdulo
e a funo pol-fi que nos permite obter o argumento tero de usar as
operaes do tipo coordenadas rectangulares:
(defun pol-ro (c)
(sqrt (+ (quadrado (cx c)) (quadrado (cy c)))))
(defun pol-fi (c)
(atan (cy c) (cx c)))
Eis alguns exemplos do uso destas funes:
19
_$ (pol (sqrt 2) (/ pi 4))
(1.0 1.0)
_$ (pol 1 0)
(1.0 0.0)
_$ (pol 1 (/ pi 2))
(6.12323e-017 1.0)
_$ (pol 1 pi)
(-1.0 1.22465e-016)
Uma outra operao bastante til a que, dado um ponto P = (x, y) e
um vector com origem em P e descrito em coordenadas polares por uma
distncia e um ngulo , devolve o ponto localizado na extremidade destino
do vector, tal como visualizado na Figura 7. A trigonometria permite-nos
facilmente concluir que as coordenadas do ponto destino so dadas por P

=
(x + cos , y + sin).
19
Note-se, nestes exemplos, que alguns valores das coordenadas no so zero como seria
expectvel, mas sim valores muito prximos de zero que resultam de erros de arredondamento.
48
P

Figura 7: O deslocamento de um ponto em coordenadas polares.


A traduo directa da funo para Lisp :
(defun +pol (p ro fi)
(xy (+ (cx p) (
*
ro (cos fi)))
(+ (cy p) (
*
ro (sin fi)))))
No entanto relativamente evidente que esta funo est a fazer parte do
trabalho que j feito pela funo +xy, nomeadamente no que diz respeito
soma das coordenadas do ponto p com as componentes que resultam da
converso de coordenadas polares para rectangulares. Assim, possvel sim-
plicar esta funo escrevendo apenas:
(defun +pol (p ro fi)
(+xy p
(
*
ro (cos fi))
(
*
ro (sin fi))))
Como exemplos de utilizao, temos:
_$ (+pol (xy 1 2) (sqrt 2) (/ pi 4))
(2.0 3.0)
_$ (+pol (xy 1 2) 1 0)
(2.0 2.0)
_$ (+pol (xy 1 2) 1 (/ pi 2))
(1.0 3.0)
Uma observaco atenta das funes +xy e +pol permite-nos constatar que
elas partilham um mesmo comportamento: ambas recebem um ponto e um
vector a somar a esse ponto para produzir um novo ponto: esse vector
descrito pelos parmetros x e y no primeiro caso e por e no segundo.
O facto de ambas as funes partilharem um comportamento leva-nos na-
turalmente a pensar na sua possvel generalizao, atravs da denio de
uma nica funo +c que, dado um ponto P
0
e outro ponto P
1
representando
a extremidade nal de um vector com extremidade inicial na origem, devolve
49
P
0

x
P

x
P
1
Figura 8: O deslocamento de um ponto por adio de um vector.
o ponto que resulta de somar esse vector ao primeiro ponto, tal como est ilus-
trado da Figura 8. Naturalmente, quer o ponto P
0
quer o ponto P
1
podem
ser especicados em qualquer sistema de coordenadas desde que seja possvel
relacionar esse sistema com o sistema de coordenadas rectangulares.
Para denirmos esta funo a abordagem mais simples ser explorar as
propriedades aditivas das coordenadas rectangulares:
(defun +c (p0 p1)
(xy (+ (cx p0) (cx p1))
(+ (cy p0) (cy p1))))
Uma vez que as coordenadas polares esto representadas em termos de co-
ordenadas rectangulares, mesmo quando especicamos coordenadas polares
a operao +c continua a funcionar correctamente.
4.12 A funo command
Apartir do momento emque sabemos construir coordenadas torna-se possvel
utilizar um conjunto muito vasto de operaes grcas do Auto Lisp. Existem
trs maneiras diferentes de se invocar essas operaes grcas mas, por agora,
vamos explorar apenas a mais simples: a funo command.
A funo command aceita um nmero arbitrrio de expresses que vai ava-
liando e passando os valores obtidos para o AutoCad medida que o AutoCad
os vai requerendo.
20
No caso de utilizao mais comum, a funo command
recebe uma cadeia de caracteres que descreve o comando AutoCad que se pre-
tende executar seguido de qualquer nmero de argumentos que sero usados
como os dados necessrios para a execuo desse comando.
A vantagem da funo command permitir criar programas completos que
criam entidades grcas tal como um normal utilizador de AutoCad o pode-
ria fazer de forma manual. A ttulo de exemplo, consideremos a criao de um
20
Este comportamento mostra que, na realidade, command no pertence ao conjunto das fun-
es normais pois, ao contrrio destas, s avalia os argumentos medida que eles vo sendo
necessrios.
50
crculo. Para se criar um crculo em AutoCad pode-se usar o comando circle
e fornecer-lhe as coordenadas do centro e o raio do crculo. Se pretenderemos
criar o mesmo crculo a partir do Auto Lisp, ao invs de invocarmos interac-
tivamente o comando AutoCad circle e de lhe fornecermos os dados neces-
srios, podemos simplesmente invocar a funo command e passar-lhe todos
os dados necessrios como argumentos, comeando pela string "circle", se-
guida das coordenadas do centro do crculo e, por ltimo, seguida do raio do
crculo.
Para concretizarmos o exemplo, consideremos a criao de um crculo de
raio r = 1 centrado na posio (x, y) = (2, 3). A invocao Auto Lisp que cria
este crculo a seguinte:
_$ (command "circle" (list 2 3) 1)
nil
Como se pode ver pelo exemplo, as coordenadas do centro do crculo fo-
ram especicadas atravs da criao de uma lista. No entanto, como referimos
na seco 4.10, vamos evitar a especicao de coordenadas directamente em
termos da sua representao como listas e vamos, em seu lugar, usar as opera-
es do tipo. Assim, a expresso anterior ca mais correcta na seguinte forma:
_$ (command "circle" (xy 2 3) 1)
nil
Como se pode ver tambm, a invocao da funo command devolve nil
como resultado.
Umoutro exemplo da utilizao desta funo na colocao de umtexto na
nossa rea de desenho. Para isso, podemos usar novamente a funo command
mas, desta vez, os argumentos a passar sero outros, nomeadamente, a cadeia
de caracteres "text", as coordenadas onde pretendemos colocar o (canto in-
ferior esquerdo do) texto, um nmero que representa a altura do texto, um
nmero que representa o ngulo (em radianos) que a base do texto dever
fazer com a horizontal e, nalmente, uma cadeia de caracteres com o texto a
inserir. Eis um exemplo:
_$ (command "text" (xy 1 1) 1 0 "AutoCad")
nil
O resultado da avaliao das duas invocaes anteriores visvel da Fi-
gura 9.
Finalmente, a funo command pode ser usada para alterar os parmetros
de funcionamento do AutoCad. Por exemplo, para desligar os Object Snaps
podemos fazer:
_$ (command "osnap" "off")
nil
importante memorizar esta ltima expresso pois, sem a sua invocao,
todos os usos da funo command estaro sob o efeito de Object Snaps, fazendo
51
Figura 9: Um crculo com o texto "AutoCad".
Figura 10: Crculos e textos especicados usando coordenadas polares.
comque as coordenadas que indicamos para as nossas guras geomtricas no
sejam estritamente respeitadas pelo AutoCad, que as arredondar de acordo
com a malha do Object Snaps.
Como exemplo da utilizao de comandos em Auto Lisp, a Figura 10 mos-
tra o resultado da avaliao das seguintes expresses onde usamos coordena-
das polares para desenhar crculos e texto:
(command "erase" "all" "")
(command "circle" (pol 0 0) 4)
(command "text" (+pol (pol 0 0) 5 0)
1 0 "Raio: 4")
(command "circle" (pol 4 (/ pi 4)) 2)
(command "text" (+pol (pol 4 (/ pi 4)) 2.5 0)
0.5 0 "Raio: 2")
(command "circle" (pol 6 (/ pi 4)) 1)
(command "text" (+pol (pol 6 (/ pi 4)) 1.25 0)
0.25 0 "Raio: 1")
(command "zoom" "e")
Exerccio 4.12.1 Refaa o desenho apresentado na Figura 10 mas utilizando apenas
coordenadas rectangulares.
52
Exerccio 4.12.2 Dena uma funo denominada circulo-e-raio que, dadas as
coordenadas do centro do crculo e o raio desse crculo, cria o crculo especicado no
AutoCad e, semelhana do que se v na Figura 10, coloca o texto a descrever o raio
do crculo direita do crculo. O texto dever ter um tamanho proporcional ao raio
do crculo.
Exerccio 4.12.3 Utilize a funo circulo-e-raio denida na pergunta anterior
para reconstituir a imagem apresentada na Figura 10.
Existem algumas particularidades do comportamento da funo command
que importante discutir. Para as compreendermos preciso recordar que a
funo command simula a interaco do utilizador com o AutoCad. Consi-
deremos ento um exemplo de uma interaco: imaginemos que estamos em
frente interface do AutoCad e pretendemos apagar todo o contedo da nossa
rea de desenho no AutoCad. Para isso, podemos invocar o comando erase
do AutoCad, o que podemos fazer escrevendo as letras e-r-a-s-e e premindo
enter no nal. Acontece que o comando no pode ser imediatamente execu-
tado pois o AutoCad precisa de saber mais informao, em particular, o que
que para apagar. Para isso, o AutoCad pede-nos para seleccionar um ou
mais objectos para apagar. Nessa altura, se respondermos com a palavra all e
premirmos novamente a tecla enter, o AutoCad selecciona todos os objectos
mas ca a aguardar que indiquemos que terminmos a seleco de objectos, o
que se pode fazer premindo simplesmente a tecla enter.
Ora para que a funo command possa simular a interaco que acabmos
de descrever, ela tem de passar ao AutoCad todas as informaes necess-
rias e tem de o fazer medida que o AutoCad precisa delas. Assim, cada
sequncia de teclas que foi por ns dada ao AutoCad dever ser agora dada
na forma de string como argumento funo command. No entanto, como no
faz muito sentido obrigar o utilizador a especicar, numa string o premir da
tecla enter, a funo command assume que, aps passar todos os caracteres
de uma string ao AutoCad, deve passar-lhe tambm o correspondente premir
da tecla enter.
Tentemos agora, luz desta explicao, construir a invocao da funo
command que simula a interaco anterior. O primeiro passo da avaliao da
expresso , como referimos, o passar da sequncia de letras e-r-a-s-e segui-
das do premir virtual da tecla enter, o que podemos fazer escrevendo:
(command "erase" ...)
Em seguida, sabemos que o AutoCad nos vai pedir para seleccionarmos
os objectos a apagar, pelo que escrevemos a string com a palavra all que a
funo ir passar ao AutoCad, novamente terminando-a com o premir virtual
da tecla enter:
(command "erase" "all" ...)
Finalmente, sabemos que depois desta interaco, o AutoCad vai continuar
espera que indiquemos que terminmos a seleco de objectos atravs do
premir da tecla enter, o que implica que temos de indicar funo command
53
para simplesmente passar o tal premir virtual da tecla enter. Ora j sabe-
mos que a funo faz isso automaticamente aps passar os caracteres de uma
string pelo que, se no queremos passar caracteres alguns mas apenas a tecla
enter ento, logicamente, temos de usar uma string vazia, ou seja:
(command "erase" "all" "")
Assim, a string vazia, quando usada como argumento de command, equi-
valente a premir a tecla enter na linha de comandos do AutoCad.
claro que, se na sequncia de uma invocao da funo command, o Au-
toCad car espera de dados, novas invocaes da funo command podero
providenciar esses dados ou o utilizador poder dar essa informao directa-
mente no AutoCad. Isto quer dizer que a invocao anterior pode tambm ser
feita na forma:
(command "erase")
(command "all")
(command "")
Como se pode constatar pelo exemplo anterior, a funo command termina
assim que conseguir passar todos os argumentos que tem para o AutoCad, in-
dependentemente de eles serem sucientes ou no para o AutoCad conseguir
completar o pretendido. Se no forem, o AutoCad limita-se a continuar es-
pera que lhe forneamos, via command ou directamente na interface, os dados
que lhe faltam, o que nos permite implementar um processo de colaborao
com o AutoCad: parte do que se pretende feito no lado do Auto Lisp e a
parte restante no lado do AutoCad.
Por exemplo, imaginemos que pretendemos criar um crculo num dado
ponto mas queremos deixar ao utilizador a escolha do raio. Uma soluo ser
iniciar a construo do crculo centrado num dado ponto atravs da funo
command mas aguardar que o utilizador termine essa construo indicando
explicitamente no AutoCad (por exemplo, usando o rato) qual o raio do cr-
culo pretendido. Assim, iniciariamos o comando com:
(command "circle" (xy 0 0))
e o utilizador iria ento ao AutoCad terminar a criao do crculo atravs da
indicao do raio.
Um problema um pouco mais complicado ser criar um crculo de raio xo
mas deixar ao utilizador a escolha do centro. A complicao deriva do facto de
no sabermos quais so as coordenadas do centro mas queremos passar o raio:
se nos falta o argumento do meio, ou seja, a posio do centro do crculo,
no podemos passar o do m, ou seja, o raio do crculo.
H vrias solues para este problema mas, por agora iremos explorar ape-
nas uma. Para contornar o problema, o AutoCad permite a utilizao do carc-
ter especial \ para indicar que se pretende suspender momentaneamente a
passagem de argumentos para o AutoCad, para se retomar essa passagem as-
sim que o AutoCad obtenha o valor correspondente ao argumento que no
54
foi passado. Para facilitar a legibilidade dos programas, o smbolo pause de-
signa precisamente a string que contm esse nico carcter \. A seguinte
interaco mostra um exemplo da utilizao desta possibilidade:
21
_$ pause
"\\"
_$ (command "circle" pause 3)
nil
Um outro aspecto importante da funo command prende-se com a passa-
gem de nmeros e coordenadas (representadas por listas de nmeros). Em-
bora nos exemplos anteriores estes tipos de dados tenham sido directamente
passadas funo command, na realidade tambm podem ser passados si-
mulando o premir das teclas correspondentes. Isto quer dizer que possvel
criar um crculo com centro no ponto (2, 3) e raio 1 atravs da expresso:
(command "circle" "2,3" "1")
O que acontece, na prtica, que os argumentos da funo command, para
alm de s serem avaliados quando so necessrios, so tambm automatica-
mente convertidos para o formato pretendido pelo AutoCad. Isto permite-nos
trabalhar as propriedades das entidades geomtricas no formato que nos
mais conveniente (nmeros, coordenadas, etc) e deixar funo command a
responsabilidade de converter os valores para o formato apropriado para o
AutoCad.
Exerccio 4.12.4 Pretendemos colocar duas circunferncias de raio unitrio em torno
da origem de modo a que quem encostadas uma outra, tal como se ilustra no
seguinte desenho:
Escreva uma sequncia de expresses que, quando avaliadas, produzem a gura
anterior.
Exerccio 4.12.5 Pretendemos colocar quatro circunferncias de raio unitrio emtorno
da origem de modo a que quem encostadas umas s outras, tal como se ilustra no
seguinte desenho:
21
Note-se que, tal como referido na Tabela ??, o carcter \ um carcter de escape e por
isso que tem de ser escrito em duplicado.
55
Escreva uma sequncia de expresses que, quando avaliadas, produzem a gura
anterior.
Exerccio 4.12.6 Pretendemos colocar trs circunferncias de raio unitrio em torno
da origem de modo a que quem encostadas umas s outras, tal como se ilustra no
seguinte desenho:
Escreva uma sequncia de expresses que, quando avaliadas, produzem a gura
anterior.
4.13 Variantes de Comandos
Quando fornecemos um nome na linha de comando do AutoCad, ele tenta
perceber o que pedido seguindo um algoritmo que involve os seguintes pas-
sos:
22
1. O nome pesquisado na lista de comandos do AutoCad. Se o nome
est na lista, ento, se o nome precedido de um ponto ., executa o
comando e termina, caso contrrio pesquisa o nome na lista de comandos
no-denidos
23
e, se no o encontrar, executa o comando e termina.
24
2. Onome pesquisado na lista de comandos externos denidos no cheiro
de parmetros acad.pgp. Se o encontrar, executa o comando e termina.
3. O nome pesquisado na lista de comandos denidos pelo Auto Lisp. Se
o encontrar ento, primeiro, verica se um comando de carregamento
automtico e, se for, o programa correspondente carregado e, segundo,
executa o comando e termina.
4. O nome pesquisado na lista de sinnimos (aliases) denidos no cheiro
de parmetros do programa. Se o encontrar, substitui o nome pela sua
expanso e volta ao princpio.
5. Termina com uma mensagem de erro indicando que o nome desconhe-
cido.
22
Por motivos pedaggicos, esta descrio uma simplicao da realidade.
23
Um comando no-denido no a mesma coisa que um comando indenido. O primeiro
corresponde a um comando conhecido que foi explicitamente declarado como no denido
enquanto o segundo corresponde a um comando totalmente desconhecido.
24
Este comportamento permite que se possam tornar comandos como no-denidos e, ainda
assim, pode execut-los desde que se preceda o seu nome de um ponto.
56
Repare-se que o algoritmo anterior fala de comandos cujo nome prece-
dido de um ponto, de comandos no denidos, comandos externos, etc. Todas
estas variedades existem porque, na realidade, possvel redenir ou tornar
como no denidos os comandos pr-denidos do AutoCad. Isto implica que
quando invocamos um comando como, por exemplo, circle, estamos na re-
alidade a invocar a mais recente denio que foi feita para esse comando. S
no caso de no ter sido feita qualquer redenio do comando e de este no
ter sido tornado no denido que iremos invocar a denio original. A con-
sequncia que, no sabendo se foi feita uma redenio ou se o comando no
foi tornado como no denido, no podemos ter a certeza do que vai realmente
ser executado.
Como se pode ver pelo algoritmo descrito acima, o AutoCad admite uma
variante para todos os comandos: se o nome do comando comear com o ca-
rcter ponto . ento feita a execuo do comando pr-denido do Auto-
Cad. Desta forma, este pequeno truque permite-nos ultrapassar qualquer
redenio ou no denio de um comando.
Uma outra caracterstica do AutoCad que pode complicar a utilizao da
funo command a internacionalizao: em diferentes pases, o AutoCad uti-
liza os nomes dos comandos traduzidos para diferentes lnguas. Por exem-
plo, o comando circle escreve-se kreis no AutoCad Alemo, cercle no
Francs, cerchio no Italiano, krunice no Checo e circulo no Espanhol.
Assim, se tivermos feito um programa que invoca o comando circle e ten-
tarmos executar esse comando num AutoCad preparado para outra lngua,
iremos obter um erro por o comando ser desconhecido nessa lngua.
Para evitar este problema, o AutoCad admite ainda outra variante para
todos os comandos: se o nome do comando comear com o carcter _ ento
feita a execuo do comando na lngua original do AutoCad, que o Ingls.
A combinao destas duas variantes possvel. O nome _.circle (ou
._circle) indica a verso original do comando, independentemente de alte-
raes lingusticas ou redenies do comando.
Para evitar problemas, de agora em diante iremos sempre utilizar esta con-
veno de preceder com os caracteres _. todos os comandos que usarmos
na operao command.
Exerccio 4.13.1 Redena e teste a funo circulo-e-raio de modo a usar os co-
mandos pr-denidos do AutoCad, independentemente de redenies de comandos
ou mudanas de lngua.
Exerccio 4.13.2 Dena a funo comando-pre-definido que, dado o nome de um
comando em ingls, devolve esse nome convenientemente modicado para permitir
aceder ao comando correspondente pr-denido no AutoCad independentemente da
lngua em que este esteja.
4.14 ngulos em Comandos
Alguns dos comandos do AutoCad necessitam de saber raios e ngulos em si-
multneo. Por exemplo, para criar um polgono regular, o comando polygon
necessita de saber quantos lados ele dever ter, qual o centro do polgono, se
57
ele vai estar inscrito numa circunferncia ou circunscrito numa circunferncia
e, nalmente o raio dessa circunferncia e o ngulo que o primeiro vrtice
do polgono faz com o eixo dos x. Este dois ltimos parmetros, contudo, no
podem ser fornecidos separadamente, sendo necessrio especic-los de uma
forma conjunta, atravs de uma string em que se junta o raio e o ngulo se-
parados pelo carcter < (representando um ngulo) e precedidos do carc-
ter @ (representando um incremento relativamente ao ltimo ponto dado,
que era o centro da circunferncia). Por exemplo, o raio 2 com um ngulo de
30
o
escreve-se "@2<30". Note-se que o ngulo tem de estar em graus. Se, ao
invs de fornecermos esta string fornecermos apenas um nmero, o AutoCad
ir tratar esse nmero como o raio e, mesmo que lhe tentemos fornecer outro
nmero para o ngulo, ir assumir que o ngulo zero.
Uma vez que, na maior parte dos casos, os raios e ngulos sero parme-
tros das nossas funes e ainda que, do ponto de vista matemtico, prefervel
trabalhar em radianos, conveniente denir uma funo que, a partir do raio e
ngulo em radianos, produz a string apropriada com o ngulo em graus. Para
isso, conveniente usarmos a funo strcat para concatenarmos as strings
parciais que sero produzidas atravs da funo rtos que converte um n-
mero numa string. Assim, temos:
(defun raio&angulo (raio angulo)
(strcat "@"
(rtos raio)
"<"
(rtos (graus<-radianos angulo))))
Usando esta funo agora trivial criarmos polgonos com diferentes n-
gulos de rotao. Por exemplo, a seguinte sequncia de comandos produz a
imagem representada na Figura 11:
(command "_.polygon" 3
(xy 0 0) "_Inscribed" (raio&angulo 1 0))
(command "_.polygon" 3
(xy 0 0) "_Inscribed" (raio&angulo 1 (/ pi 3)))
(command "_.polygon" 4
(xy 3 0) "_Inscribed" (raio&angulo 1 0))
(command "_.polygon" 4
(xy 3 0) "_Inscribed" (raio&angulo 1 (/ pi 4)))
(command "_.polygon" 5
(xy 6 0) "_Inscribed" (raio&angulo 1 0))
(command "_.polygon" 5
(xy 6 0) "_Inscribed" (raio&angulo 1 (/ pi 5)))
4.15 Efeitos Secundrios
Vimos anteriormente que qualquer expresso Lisp tem um valor. No entanto,
aquilo que se pretende de uma expresso que use a funo command no
saber qual o seu valor mas sim qual o efeito que produzido num determinado
58
Figura 11: Tringulos, quadrados e pentgonos sobrepostos com diferentes
ngulos de rotao.
desenho. De facto, a execuo de um comando AutoCad produz, em geral,
uma alterao do desenho actual, sendo irrelevante o seu valor.
Este comportamento da funo command fundamentalmente diferente
do comportamento das funes que vimos at agora pois, anteriormente, as
funes eram usadas para computar algo, i.e., para produzir um valor a par-
tir da sua invocao com determinados argumentos e, agora, no o valor
que resulta da invocao do comando que interessa mas sim o efeito secundrio
(tambm chamado efeito colateral) que interessa.
Contudo, mesmo no caso em que apenas nos interessa o efeito secundrio,
necessrio continuar a respeitar a regra de que, em Lisp, qualquer expresso
tem um valor e, por isso, tambm uma invocao de funo tem de produ-
zir um valor como resultado. por este motivo que a invocao da funo
command devolve sempre nil como resultado. Obviamente que qualquer ou-
tro valor serviria (pois no suposto ser usado) mas convenciona-se que nos
casos em que no h um valor mais relevante a devolver deve-se devolver nil
(que, em Latim, signica nada).
25
Um dos aspectos importantes da utilizao de efeitos secundrios est na
possibilidade da sua composio. A composio de efeitos secundrios faz-se
atravs da sua sequenciao, i.e., da realizao sequencial dos vrios efeitos. Na
seco seguinte iremos ver um exemplo da composio de efeitos secundrios.
25
Em tutoriais de Auto Lisp aparece por vezes a sugesto de terminar a denio de funes
que apenas realizam efeitos secundrios com a expresso de escrita (princ). De facto, quando
invocada desta forma, a funo princ no s no escreve nada como aparenta no devolver
nada:
_$ (princ)
_$
No entanto, na realidade, a expresso anterior devolveu, de facto, um valor: um smbolo cuja
representao externa no escrita no terceiro passo do ciclo read-eval-print. Embora invisvel,
este smbolo especial no deixa de ser um valor e pode ser usado como qualquer outro va-
lor, embora a sua invisibilidade possa provocar resultados possivelmente menos expectveis,
como a seguinte comparao mostra:
_$ (cons 1 2)
(1 . 2)
_$ (cons (princ) (princ))
( . )
59
Figura 12: O Templo Grego de Segesta, exemplicando alguns aspectos da
Ordem Drica. Este templo nunca chegou a ser terminado, sendo visvel, por
exemplo, a falta das caneluras nas colunas. Fotograa de Enzo De Martino.
4.16 A Ordem Drica
Na Figura 12 apresentamos uma imagem do templo grego de Segesta. Este
templo, que nunca chegou a ser acabado, foi construdo no sculo quinto an-
tes de Cristo e representa um excelente exemplo da Ordem Drica, a mais an-
tiga das trs ordens da arquitectura Grega clssica. Nesta ordem, uma coluna
caracteriza-se por ter um fuste, um coxim e um baco. O baco tem a forma
de uma placa quadrada que assenta sobre o coxim, o coxim assemelha-se a um
tronco de cone invertido e assenta sobre o fuste, e o fuste assemelha-se a um
tronco de cone com vinte caneluras em seu redor. Estas caneluras assemelham-
se a uns canais semi-circulares escavados ao longo da coluna.
26
Quando os Ro-
manos copiaram a Ordem Drica introduziram-lhe um conjunto de alteraes,
em particular, nas caneluras que, muitas vezes, so simplesmente eliminadas.
Nesta seco vamos esquematizar o desenho de uma coluna Drica (sem
caneluras). Do mesmo modo que uma coluna Drica se pode decompor nos
seus componentes fundamentaiso fuste, o coxim e o bacotambm o dese-
nho da coluna se poder decompor no desenho dos seus componentes. Assim,
vamos denir funes para desenhar o fuste, o coxim e o baco. A Figura 13
apresenta um modelo de referncia. Comecemos por denir uma funo para
o desenho do fuste:
(defun fuste ()
(command "_.line"
26
Estas colunas apresentamainda uma deformao intencional denominada entasis. Aentasis
consiste em dar uma ligeira curvatura coluna e, segundo alguns autores, destina-se a corrigir
uma iluso de ptica que faz as colunas direitas parecerem encurvadas.
60
(0, 0)
x
y
(0.8, 10)
(1, 0) (1, 0)
(0.8, 10)
(1, 10.5) (1, 10.5)
(1, 11) (1, 11)
Figura 13: Uma coluna Drica de referncia.
(xy -0.8 10)
(xy -1 0)
(xy 1 0)
(xy 0.8 10)
(xy -0.8 10)
""))
Neste exemplo, a funo command executa o comando AutoCad line que,
dada uma sequncia de pontos, constri uma linha poligonal com vrtices nes-
ses pontos. Para se indicar o m da sequncia de pontos usa-se uma string
vazia. Naturalmente, a invocao da funo fuste ter, como efeito secund-
rio, a criao do fuste da coluna na rea de desenho do AutoCad. Uma outra
possibilidade, eventualmente mais correcta, seria pedir ao AutoCad a criao
de uma linha fechada, algo que podemos fazer com a opo "close" no lugar
do ltimo ponto, i.e.:
(defun fuste ()
(command "_.line"
(xy -0.8 10)
(xy -1 0)
(xy 1 0)
(xy 0.8 10)
"_close"))
Note-se que o resultado do comando line a criao de um conjunto
de segmentos de recta. Cada um destes segmentos de recta uma entidade
individual que pode ser seleccionada e modicada independentemente dos
restantes. Para o caso de no pretendermos esse tratamento independente,
o AutoCad disponibiliza polilinhas (tambm conhecidas por plines). Estas so
criadas pelo comando pline que, neste contexto, difere do comando line no
61
facto de ter como resultado a criao de uma nica entidade composta pelos
vrios segmentos.
27
Para completar a gura, ainda necessrio denir uma funo para o co-
xim e outra para o baco. No caso do coxim, o raciocnio semelhante:
(defun coxim ()
(command "_.line"
(xy -0.8 10)
(xy -1 10.5)
(xy 1 10.5)
(xy 0.8 10)
"_close"))
No caso do baco, podemos empregar uma abordagem idntica ou po-
demos explorar outro comando do AutoCad ainda mais simples destinado
construo de rectngulos. Este comando apenas necessita de dois pontos para
denir completamente o rectngulo:
(defun abaco ()
(command "_.rectangle"
(xy -1 10.5)
(xy 1 11)))
Finalmente, vamos denir uma funo que desenha as trs partes da co-
luna:
(defun coluna ()
(fuste)
(coxim)
(abaco))
Repare-se, na funo coluna, que ela invoca sequencialmente as funes
fuste, coxim e, nalmente, abaco. Para percebermos o funcionamento da
funo coluna importante saber que quando invocamos uma funo que
possui uma sequncia de expresses, o Lisp avalia sequencialmente cada uma
das expresses, descartando o seu valor, at chegar ltima cujo valor usado
como valor nal da funo. O facto de se descartarem todos os valores ex-
cepto o ltimo mostra que, numa sequenciao de expresses, o que importa
o efeito secundrio da sua avaliao. A sequenciao o exemplo mais sim-
ples de uma estrutura de controle. Em termos muito grosseiros, uma estrutura
de controle um mecanismo das linguagens de programao que indica ao
computador a ordem pela qual pretendemos que ele execute o programa.
A Figura 14 mostra o resultado da invocao da funo coluna.
4.17 Parameterizao de Figuras Geomtricas
Infelizmente, a coluna que crimos na seco anterior tem todas as suas di-
menses xas, pelo que ser difcil encontrarmos outras situaes em que pos-
samos reutilizar a funo que denimos. Naturalmente, esta funo seria mais
27
Outras diferenas incluem o facto de as plines poderem ter espessura e estarem limitadas a
um plano.
62
Figura 14: Uma coluna drica desenhada pelo AutoCad.
til se a criao da coluna fosse parameterizvel, i.e., se a criao dependesse
dos vrios parmetros que caracterizam a coluna como, por exemplo, as coor-
denadas da base da coluna, a altura do fuste, do coxim e do baco, os raios da
base e do topo do fuste, etc.
Para se compreender a parameterizao destas funes vamos comear por
considerar o fuste representado esquematicamente na Figura 15.
O primeiro passo para parameterizarmos um desenho geomtrico consiste
na identicao dos parmetros relevantes. No caso do fuste, um dos par-
metros bvios a localizao espacial desse fuste, i.e., as coordenadas de um
ponto de referncia em relao ao qual fazemos o desenho do fuste. Assim,
comecemos por imaginar que o fuste ir ser colocado com o centro da base
num imaginrio ponto P de coordenadas arbitrrias (x, y). Para alm deste
parmetro, temos ainda de conhecer a altura do fuste a e os raios da base r
b
e
do topo r
t
do fuste.
Para mais facilmente idealizarmos um processo de desenho, conveniente
assinalarmos no esquema alguns pontos de referncia adicionais. No caso do
fuste, uma vez que o seu desenho , essencialmente, um trapzio, basta-nos
idealizar o desenho deste trapzio atravs de uma sucesso de linhas rectas
dispostas ao longo de uma sequncia de pontos P
1
, P
2
, P
3
e P
4
, pontos esses
que conseguimos calcular facilmente a partir do ponto P.
Desta forma, estamos em condies de denir a funo que desenha o
fuste. Para tornar mais claro o programa, vamos empregar os nomes a-fuste,
r-base e r-topo para caracterizar a altura a, o raio da base r
b
e o raio do topo
r
t
, respectivamente. A denio ca ento:
(defun fuste (p a-fuste r-base r-topo)
(command "_.line"
(+xy p (- r-topo) a-fuste)
(+xy p (- r-base) 0)
(+xy p (+ r-base) 0)
(+xy p (+ r-topo) a-fuste)
"_close"))
63
r
t
r
b
a
P = (x, y)
P
4
= (x r
b
, y)
P
1
= (x r
t
, y + a) P
2
= (x + r
t
, y + a)
P
3
= (x + r
b
, y)
Figura 15: Esquema do desenho do fuste de uma coluna.
r
b
r
t
a
P = (x, y)
P
1
= (x r
b
, y)
P
2
= (x r
t
, y + a) P
3
= (x + r
t
, y + a)
P
4
= (x + r
b
, y)
Figura 16: Esquema do desenho do coxim de uma coluna.
Em seguida, temos de especicar o desenho do coxim. Mais uma vez,
convm pensarmos num esquema geomtrico, tal como apresentamos na Fi-
gura 16.
Tal como no caso do fuste, a partir de umponto P correspondente ao centro
da base do coxim, podemos computar as coordenadas dos pontos que esto
nas extremidades dos segmentos de recta que delimitam o desenho do coxim.
Usando estes pontos, a denio da funo ca com a seguinte forma:
(defun coxim (p a-coxim r-base r-topo)
(command "_.line"
(+xy p (- r-base) 0)
(+xy p (- r-topo) a-coxim)
(+xy p (+ r-topo) a-coxim)
(+xy p (+ r-base) 0)
"_close"))
Terminado o fuste e o coxim, preciso denir o desenho do baco. Para
isso, fazemos um novo esquema que apresentamos na Figura 17.
64
l
a
P = (x, y)
P
1
= (x
l
2
, y)
P
2
= (x +
l
2
, y + a)
Figura 17: Esquema do desenho do baco de uma coluna.
Mais uma vez, vamos considerar como ponto de partida o ponto P no cen-
tro da base do baco. A partir deste ponto, podemos facilmente calcular os
pontos P
1
e P
2
que constituem os dois extremos do rectngulo que representa
o alado do baco. Assim, temos:
(defun abaco (p a-abaco l-abaco)
(command "_.rectangle"
(+xy p (/ l-abaco -2.0) 0)
(+xy p (/ l-abaco +2.0) a-abaco)))
Finalmente, para desenhar a coluna completa, temos de combinar os dese-
nhos do fuste, do coxim e do baco. Apenas precisamos de ter em conta que,
tal como a Figura 18 demonstra, o raio do topo do fuste coincide coincide com
o raio da base do coxim e o raio do topo do coxim metade da largura do
baco. A mesma Figura mostra tambm que as coordenadas da base do co-
xim correspondem a somar a altura do fuste s coordenadas da base do fuste
e as coordenadas da base do baco correspondem a somar a altura do fuste e
a altura do coxim s coordenadas da base do fuste.
Tal como zmos anteriormente, vamos dar nomes mais claros aos par-
metros da Figura 18. Usando os nomes p, a-fuste, r-base-fuste, a-coxim,
r-base-coxim, a-abaco e l-abaco no lugar de, respectivamente, P, a
f
,
r
bf
, a
c
, r
bc
, a
a
e l
a
, temos:
(defun coluna (p
a-fuste r-base-fuste
a-coxim r-base-coxim
a-abaco l-abaco)
(fuste p a-fuste r-base-fuste r-base-coxim)
(coxim (+xy p 0 a-fuste) a-coxim r-base-coxim (/ l-abaco 2.0))
(abaco (+xy p 0 (+ a-fuste a-coxim)) a-abaco l-abaco))
Com base nestas funes, podemos agora facilmente experimentar varia-
es de colunas. As seguintes invocaes produzem o desenho apresentado
na Figura 19.
(coluna (xy 0 0) 9 0.5 0.4 0.3 0.3 1.0)
(coluna (xy 3 0) 7 0.5 0.4 0.6 0.6 1.6)
(coluna (xy 6 0) 9 0.7 0.5 0.3 0.2 1.2)
(coluna (xy 9 0) 8 0.4 0.3 0.2 0.3 1.0)
(coluna (xy 12 0) 5 0.5 0.4 0.3 0.1 1.0)
(coluna (xy 15 0) 6 0.8 0.3 0.2 0.4 1.4)
65
a
f
ac
aa
la
r
bf
r
bc
P
Figura 18: A composio do fuste, coxim e baco.
Figura 19: Variaes de colunas dricas.
66
Como bvio pela anlise desta gura, nem todas as colunas desenhadas
obedecem aos cnones da ordem Drica. Mais frente iremos ver que modi-
caes sero necessrias para evitar este problema.
4.18 Documentao
Na funo coluna, a-fuste a altura do fuste, r-base-fuste o raio da
base do fuste, r-topo-fuste o raio do topo do fuste, a-coxim a altura do
coxim, a-abaco a altura do baco e, nalmente, r-abaco o raio do baco.
Uma vez que a funo j tem vrios parmetros e o seu signicado poder no
ser bvio para quem l a denio da funo pela primeira vez, conveniente
documentar a funo. Para isso, a linguagem Lisp providencia uma sintaxe
especial: sempre que surge o carcter ;, a processo de leitura do Lisp ignora
tudo o que vem a seguir at ao m da linha. Isto permite-nos escrever texto
nos nossos programas sem correr o risco de o Lisp tentar perceber o que l est
escrito.
Usando documentao, o nosso programa completo para desenhar colunas
dricas ca com o seguinte aspecto:
28
;;;;Desenho de colunas doricas
;;;O desenho de uma coluna dorica divide-se no desenho do
;;;fuste, do coxim e do abaco. A cada uma destas partes
;;;corresponde uma funcao independente.
;Desenha o fuste de uma coluna dorica.
;p: coordenadas do centro da base da coluna,
;a-fuste: altura do fuste,
;r-base: raio da base do fuste,
;r-topo: raio do topo do fuste.
(defun fuste (p a-fuste r-base r-topo)
(command "_.line" ;a criacao de linhas
(+xy p (- r-topo) a-fuste) ;com a funcao command
(+xy p (- r-base) 0) ;tem de ser terminada
(+xy p (+ r-base) 0) ;com a opcao "close"
(+xy p (+ r-topo) a-fuste) ;para fechar a figura
"close"))
;Desenha o coxim de uma coluna dorica.
;p: coordenadas do centro da base do coxim,
;a-coxim: altura do coxim,
;r-base: raio da base do coxim,
;r-topo: raio do topo do coxim.
(defun coxim (p a-coxim r-base r-topo)
(command "_.line"
(+xy p (- r-base) 0)
(+xy p (- r-topo) a-coxim)
(+xy p (+ r-topo) a-coxim)
(+xy p (+ r-base) 0)
"close")) ;para fechar a figura
;Desenha o abaco de uma coluna dorica.
;p: coordenadas do centro da base da coluna,
;a-abaco: altura do abaco,
;l-abaco: largura do abaco.
28
O exemplo destina-se a mostrar as diferentes formas de documentao usadas em Lisp e
no a mostrar um exemplo tpico de programa documentado. Na verdade, o programa to
simples que no deveria necessitar de tanta documentao.
67
(defun abaco (p a-abaco l-abaco)
(command "_.rectangle"
(+xy p (/ l-abaco -2.0) 0)
(+xy p (/ l-abaco +2.0) a-abaco)))
;Desenha uma coluna dorica composta por fuste, coxim e abaco.
;p: coordenadas do centro da base da coluna,
;a-fuste: altura do fuste,
;r-base-fuste: raio da base do fuste,
;r-base-coxim: raio da base do coxim = raio do topo do fuste,
;a-coxim: altura do coxim,
;a-abaco: altura do abaco,
;l-abaco: largura do abaco = 2
*
raio do topo do coxim.
(defun coluna (p
a-fuste r-base-fuste
a-coxim r-base-coxim
a-abaco l-abaco)
;;desenhamos o fuste com a base em p
(fuste p a-fuste r-base-fuste r-base-coxim)
;;colocamos o coxim por cima do fuste
(coxim (+y p a-fuste) a-coxim r-base-coxim (/ l-abaco 2.0))
;;e o abaco por cima do coxim
(abaco (+y p (+ a-fuste a-coxim)) a-abaco l-abaco))
Desta forma, quemfor ler o nosso programa ca comuma ideia muito mais
clara do que cada funo faz, semsequer precisar de ir estudar o corpo das fun-
es. Como se v pelo exemplo anterior, pragmtica usual em Lisp usar um
diferente nmero de caracteres ; para indicar a relevncia do comentrio:
;;;; Devem comear na margem esquerda e servem para dividir o programa
em seces e dar um ttulo a cada seco.
;;; Devem comear na margem esquerda e servem para fazer comentrios
gerais ao programa que aparece em seguida. No se devem usar no in-
terior das funes.
;; Devem estar alinhadas com a parte do programa a que se vo aplicar, que
aparece imediatemente em baixo.
; Devem aparecer alinhados numa mesma coluna direita e comentam a
parte do programa imediatamente esquerda.
importante que nos habituemos a documentar as nossas denies mas
convm salientar que a documentao em excesso tambm tem desvantagens:
O cdigo Lisp deve ser sucientemente claro para que um ser humano
o consiga perceber. sempre prefervel perder mais tempo a tornar o
cdigo claro do que a escrever documentao que o explique.
Documentao que no est de acordo com o programa pior que no
ter documentao.
frequente termos de modicar os nossos programas para os adaptar
a novos ns. Quanto mais documentao existir, mais documentao
necessrio alterar para a pr de acordo com as alteraes que tivermos
feito ao programa.
68
Por estes motivos, devemos esforar-nos por escrever o cdigo mais claro
que nos for possvel e, ao mesmo tempo, providenciar documentao sucinta
e til: a documentao no deve dizer aquilo que bvio a partir da leitura do
programa.
Exerccio 4.18.1 Considere o desenho de uma seta com origem no ponto P, compri-
mento , inclinao , ngulo de abertura e comprimento da farpa , tal como se
representa em seguida:

Dena uma funo denominada seta que, a partir dos parmetros P, , , e ,


constri a seta correspondente.
Exerccio 4.18.2 Com base na soluo do exerccio anterior, dena uma funo que,
dados o ponto P, a distncia e o ngulo , desenha o norte tal como se apresenta
no esquema em baixo:
N
O desenho deve ainda obedecer s seguintes propores:
O ngulo de abertura da seta de 45

.
O comprimento da farpa de

2
.
O centro da letra N dever ser posicionado a uma distncia de

10
da extremi-
dade da seta segundo a direco da seta.
O tamanho da letra N dever ser metade da distncia .
Exerccio 4.18.3 Usando a funo seta, dena uma nova funo denominada seta-de-para
que, dados dois pontos, cria uma seta que vai do primeiro para o segundo ponto. As
farpas da seta devero ter comprimento unitrio e ngulo

8
.
Exerccio 4.18.4 Considere o desenho de uma habitao composta apenas por divi-
ses rectangulares. Pretende-se que dena a funo divisao-rectangular que
recebe como parmetros a posio do canto inferior esquerdo da diviso, o compri-
mento e a largura da diviso e um texto a descrever a funo dessa diviso na habita-
o. Com esses valores a funo dever construir o rectngulo correspondente e deve
colocar no interior desse rectngulo duas linhas de texto, a primeira com a funo da
diviso e a segunda com a rea da diviso. Por exemplo, a sequncia de invocaes
69
(divisao-rectangular (xy 0 0) 4 3 "cozinha")
(divisao-rectangular (xy 4 0) 2 3 "despensa")
(divisao-rectangular (xy 6 0) 5 3 "quarto")
(divisao-rectangular (xy 0 5) 5 4 "sala")
(divisao-rectangular (xy 5 5) 3 4 "i.s.")
(divisao-rectangular (xy 8 3) 3 6 "quarto")
produz, como resultado, a habitao que se apresenta de seguida:
4.19 Depurao
Como sabemos, errare humanum est. O erro faz parte do nosso dia-a-dia e, por
isso, em geral, sabemos lidar com ele. J o mesmo no se passa com as lingua-
gens de programao. Qualquer erro num programa tem, como consequncia,
que o programa tem um comportamento diferente daquele que era esperado.
Uma vez que fcil cometer erros, deve tambm ser fcil detect-los e
corrigi-los. actividade de deteco e correco de erros denomina-se depura-
o. Diferentes linguagens de programao providenciam diferentes mecanis-
mos para essa actividade. Neste domnio, como iremos ver, o AutoCad est
particularmente bem apetrechado.
Em termos gerais, os erros num programa podem classicar-se em erros
sintticos e erros semnticos.
4.19.1 Erros Sintticos
Os erros sintticos ocorrem quando escrevemos frases que no obedecem
gramtica da linguagem. Como exemplo prtico, imaginemos que pretendi-
amos denir uma funo que criava um nica coluna drica, que iremos de-
signar de coluna standard e que tem sempre as mesmas dimenses, no neces-
sitando de quaisquer outros parmetros. Uma possibilidade para a denio
desta funo ser:
(defun coluna-standard
(coluna (xy 0 0) 9 0.5 0.4 0.3 0.3 0.5))
70
No entanto, se avaliarmos aquela denio, o Auto Lisp ir apresentar um
erro, avisando-nos de que algo est errado:
29
; error: bad DEFUN syntax:
(COLUNA-STANDARD (COLUNA (XY 0 0) 9 0.5 0.4 0.3 0.3 0.5))
O erro de que o Auto Lisp nos est a avisar de que a forma defun que
lhe demos para avaliar no obedece sintaxe exigida para essa forma e, de
facto, uma observao atenta da forma anterior mostra que no seguimos a
sintaxe exigida para uma denio e que, tal como discutimos na seco 3.4,
era a seguinte:
(defun nome (parmetro
1
... parmetro
n
)
corpo)
O nosso erro agora bvio: esquecemo-nos da lista de parmetros. Se a
funo no tem parmetros a lista de parmetros vazia mas tem de estar l
na mesma. Uma vez que no estava, o Auto Lisp detecta e reporta um erro
sinttico, uma frase que no obedece sintaxe da linguagem.
H vrios outros tipos de erros sintticos que o Auto Lisp capaz de de-
tectar e que sero apresentados medida que os formos discutindo. O im-
portante, no entanto, no saber quais so os erros sintticos detectveis pelo
Auto Lisp, mas antes saber que o Auto Lisp capaz de vericar as expres-
ses que escrevemos e fazer a deteco de erros sintticos antes mesmo de as
avaliar.
Para isso, o Visual Lisp disponibiliza na sua interface operaes que fa-
zem essa vericao para uma seleco ou para todo o cheiro actual. Na
verso Inglesa do AutoCad, essas operaes denominam-se Check Selection
ou Check Text in Editor e esto disponveis no menu Tools. Como con-
sequncia da invocao destas operaes, o AutoCad analiza a seleco ou o
cheiro actual e escreve, numa janela parte, todos os erros sintticos encon-
trados. Nesse janela, se clicarmos duas vezes sobre uma mensagem de erro,
somos conduzidos ao local do nosso programa onde o erro ocorre.
4.19.2 Erros Semnticos
Os erros semnticos so muito diferentes dos sintticos. Um erro semntico
no um erro na escrita de uma frase da linguagem mas sim um erro no
signicado dessa frase. Dito de outra forma, um erro semntico ocorre quando
escrevemos uma frase que julgamos ter um signicado e, na verdade, ela tem
outro.
Em geral, os erros semnticos apenas so detectveis durante a invoca-
o das funes que os contm. Parte dos erros semnticos detectvel pelo
avaliador de Lisp mas h inmeros erros cuja deteco s pode ser feita pelo
prprio programador.
Como exemplo de erro semntico consideremos uma operao sem signi-
cado como seja a soma de um nmero com uma string:
29
Nem todos os dialectos e interpretadores de Lisp possuem exactamente este comporta-
mento mas, variaes parte, os conceitos so os mesmos.
71
_$ (+ 1 "dois")
; error: bad argument type: numberp: "dois"
Como se pode ver, o erro explicado na mensagem que indica que o se-
gundo argumento devia ser um nmero. Neste exemplo, o erro sucien-
temente bvio para o conseguirmos detectar imediatamente. No entanto, no
caso de programas mais complexos, isso j poder no ser assim.
Na continuao do exemplo que apresentmos na discusso sobre erros
sintticos, consideremos a seguinte modicao funo coluna-standard
que corrige a falta de parmetros mas que introduz um outro erro:
30
(defun coluna-standard ()
(coluna (xy O 0) 9 0.5 0.4 0.3 0.3 0.5))
Do ponto de vista sinttico, a funo est correcta. No entanto, quando a
invocamos surge um erro:
_$ (coluna-standard)
; error: bad argument type: numberp: nil
Como podemos ver pela resposta, o Auto Lisp protesta que um dos argu-
mentos devia ser um nmero mas, em lugar disso, era nil. Uma vez que a
funo coluna-standard no tem quaisquer argumentos, a mensagem de
erro poder ser difcil de compreender. No entanto, ela torna-se compreen-
svel quando pensamos que o erro poder no ter ocorrido na invocao da
funo coluna-standard mas sim em qualquer funo que tenha sido invo-
cada directa ou indirectamente por esta.
Para se perceber melhor onde est o erro, o Visual Lisp providencia algu-
mas operaes extremamente teis. Uma delas d pelo nome de Error Trace,
est disponvel no menu View e destina-se a mostra a cascata de invoca-
es que acabou por provocar o erro.
31
Quando executamos essa operao, o
Visual Lisp apresenta-nos, numa pequena janela, a seguinte informao:
<1> :ERROR-BREAK
[2] (+ nil -0.3)
[3] (+XY (nil 0) -0.3 9)
[4] (FUSTE (nil 0) 9 0.5 0.3)
[5] (COLUNA (nil 0) 9 0.5 0.4 0.3 0.3 0.5)
[6] (COLUNA-STANDARD)
...
Na informao acima, as reticncias representam outras invocaes que
no so relevantes para o nosso problema e que correspondem s funes
Auto Lisp cuja execuo antecede a das nossas funes.
32
A listagem apre-
sentada pelo Visual Lisp mostra, por ordem inversa, as invocaes de funes
30
Consegue detect-lo?
31
A expresso error trace pode ser traduzida para Rastreio de erros.
32
Essas funes que foram invocadas antes das nossas revelam que, na verdade, parte da
funcionalidade do Visual Lisp est ela prpria implementada em Auto Lisp.
72
que provocaram o erro. Para cada linha, o Visual Lisp disponibiliza um menu
contextual que, entre outras operaes, permite visualizarmos imediatamente
no editor qual a linha do programa em questo.
A leitura da listagem do error trace diz-nos que o erro foi provocado pela
tentativa de somarmos nil a um nmero. Essa tentativa foi feita pela funo
+xy que foi invocada pela funo fuste que foi invocada pela funo coluna
que, nalmente, foi invocada pela funo coluna-standard. Como pode-
mos ver, frente do nome de cada funo, aparecem os argumentos com que
a funo foi invocada. Estes argumentos mostram que o erro de que o Auto
Lisp se queixa na soma, na realidade, foi provocado muito antes disso, logo na
invocao da funo coluna. De facto, visvel que essa funo invocada
com um ponto cuja coordenada x nil e no um nmero como devia ser.
Esta a pista que nos permite identicar o erro: ele tem de estar na prpria
funo coluna-standard e, mais especicamente, na expresso que cria as
coordenadas que so passadas como argumento da funo coluna. Se ob-
servarmos cuidadosamente essa expresso (que assinalmos a negrito) vemos
que, de facto, est l um muito subtil erro: o primeiro argumento da funo
xy no zero mas sim a letra maisculo.
(defun coluna-standard ()
(coluna (xy O 0) 9 0.5 0.4 0.3 0.3 0.5))
Acontece que, em Auto Lisp, qualquer nome que no tenha sido previa-
mente denido tem o valor nil e, como o nome constitudo pela letra O no
est denido, a avaliao do primeiro argumento da funo xy , na verdade,
nil. Esta funo, como se limita a fazer uma lista com os seus argumentos,
cria uma lista cujo primeiro elemento nil e cujo segundo elemento zero. A
lista resultante assim passada de funo em funo at chegarmos funo
+xy que, ao tentar fazer a soma, acaba por provocar o erro.
Esta sesso de depurao mostra o procedimento habitual para deteco
de erros. A partir do momento em que o erro identicado, geralmente
fcil corrigi-lo mas convm ter presente que o processo de identicao de
erros pode ser moroso e frustrante. tambm um facto que a experincia
de deteco de erros extremamente til e que, por isso, expectvel que
enquanto essa experincia for reduzida, o processo de deteco seja mais lento.
73
5 Modelao Tridimensional
Como vimos na seco anterior, o AutoCad disponibiliza um conjunto de ope-
raes de desenho (linhas, rectngulos, crculos, etc) que nos permitem facil-
mente criar representaes bidimensionais de objectos, como sejam plantas,
alados e cortes.
Embora at este momento apenas tenhamos utilizado as capacidades de
desenho bi-dimensional do AutoCad, possvel irmos mais longe, entrando
no que se denomina por modelao tridimensional. Esta modelao visa a repre-
sentao grca de linhas, superfcies e volumes no espao tridimensional.
Nesta seco iremos estudar as operaes do AutoCad que nos permitem
modelar directamente os objectos tridimensionais.
5.1 Slidos Tridimensionais Pr-Denidos
As verses mais recentes do AutoCad disponibilizam um conjunto de ope-
raes pr-denidas que constroem um slido a partir da especicao das
suas coordenadas tridimensionais. Embora as operaes pr-denidas apenas
permitam construir um conjunto muito limitado de slidos, esse conjunto
suciente para a elaborao de modelos sosticados.
As operaes pr-denidas para criao de slidos permitem construir pa-
ralelippedos (comando box), cunhas (comando wedge), cilindros (comando
cylinder), cones (comando cone), esferas (comando sphere), toros (co-
mando torus) e pirmides (comando pyramid). Os comandos cone e pyramid
permitem ainda a construo de troncos de cone e troncos de pirmide atravs
da utilizao do parmetro "Top". Cada um destes comandos aceita vrias
opes que permitem construir slidos de diferentes maneiras.
33
A Figura 20
mostra um conjunto de slidos construdos pela avaliao das seguintes ex-
presses:
34
(command "_.box" (xyz 1 1 1) (xyz 3 4 5))
(command "_.wedge" (xyz 4 2 0) (xyz 6 6 4))
(command "_.cone" (xyz 6 0 0) 1
"_Axis" (xyz 8 1 5))
(command "_.cone" (xyz 11 1 0) 2 "_Top" 1
"_Axis" (xyz 10 0 5))
(command "_.sphere" (xyz 8 4 5) 2)
(command "_.cylinder" (xyz 8 7 0) 1 "_Axis" (xyz 6 8 7))
(command "_.pyramid" "_Sides" 5 (xyz 1 6 1) (raio&angulo 1 0)
"_Axis" (xyz 2 7 9))
(command "_.torus" (xyz 13 6 5) 2 1)
Note-se que alguns dos slidos, nomeadamente o paralelippedo e a cunha
s podem ser construdos com a base paralela ao plano XY . Esta no uma
33
Para se conhecer as especicidades de cada comando recomenda-se a consulta da docu-
mentao que acompanha o AutoCad.
34
A construo de uma pirmide exige a especicao simultnea do raio e ngulo da base.
Tal como explicado na seco 4.14, a funo raio&angulo constri essa especicao a partir
dos valores do raio e do ngulo.
74
Figura 20: Slidos primitivos em AutoCad.
verdadeira limitao do AutoCad pois possvel alterar a orientao do plano
XY atravs da manipulao do sistema de coordenadas UCSuser coordinate
system.
A partir dos comandos disponibilizados pelo AutoCad possvel denir
funes Auto Lisp que simpliquem a sua utilizao. Embora o AutoCad per-
mita vrios modos diferentes de se criar um slido, esses modos esto mais
orientados para facilitar a vida ao utilizador do AutoCad do que propriamente
para o programador de Auto Lisp. Para este ltimo, prefervel dispor de uma
funo que, a partir de um conjunto de parmetros simples, invoca o comando
correspondente em AutoCad, especicando automaticamente as opes ade-
quadas para a utilizao desses parmetros.
Para vermos um exemplo, consideremos a criao de um cilindro. Embora
o AutoCad permita construir o cilindro de vrias maneiras diferentes, cada
uma empregando diferentes parmetros, podemos considerar que os nicos
parmetros relevantes so o centro da base, o raio da base e o centro do topo.
Estes parmetros so sucientes para especicar completamente um cilindro,
permitindo orient-lo no espao como muito bem entendermos. Assim, para o
programador de Auto Lisp, basta-lhe invocar o comando AutoCad cylinder
seleccionando o modo de construo que facilita o uso deste parmetros.
precisamente isso que faz a seguinte funo:
(defun cilindro (centro-base raio centro-topo)
(command "_cylinder" centro-base raio "_Axis" centro-topo))
Usando esta funo agora mais simples denir outras estruturas mais
complexas. Por exemplo, uma cruz papal dene-se pela unio de trs cilindros
75
Figura 21: Uma cruz papal.
horizontais de comprimento progressivamente decrescente dispostos ao longo
de umcilindro vertical, tal como se pode ver na Figura 21. de salientar que os
cilindros tm todos o mesmo raio e que o seu comprimento e posicionamento
funo desse raio. Em termos de proporo, o cilindro vertical da cruz papal
tem um comprimento igual a 20 raios, enquanto que os cilindros horizontais
possuem comprimentos iguais a 14, 10 e 6 raios e o seu eixo est posicionado
a uma altura igual a 9, 13 e 17 raios. Estas propores so implementadas pela
seguinte funo:
(defun cruz-papal (p raio)
(cilindro p
raio
(+xyz p 0 0 (
*
20 raio)))
(cilindro (+xyz p (
*
-7 raio) 0 (
*
9 raio))
raio
(+xyz p (
*
+7 raio) 0 (
*
9 raio)))
(cilindro (+xyz p (
*
-5 raio) 0 (
*
13 raio))
raio
(+xyz p (
*
+5 raio) 0 (
*
13 raio)))
(cilindro (+xyz p (
*
-3 raio) 0 (
*
17 raio))
raio
(+xyz p (
*
+3 raio) 0 (
*
17 raio))))
Uma das vantagens das representaes tri-dimensionais est no facto de
elas conterem toda a informao necessria para a gerao automtica de vis-
tas bi-dimensionais, incluindo as tradicionais projeces ortogonais. Para isso,
76
Figura 22: Alado frontal, lateral e planta da cruz papal representada na Fi-
gura 21.
o AutoCad permite diferentes abordagens, desde a simples utilizao de ml-
tiplas vistas (atravs do comando mview), cada uma com uma perspectiva di-
ferente, at a criao automtica de projeces e cortes (comandos solview,
soldraw, flatshot e sectionplane, entre outros). A Figura 22 mostra o
alado frontal, o alado lateral e a planta produzidos automaticamente pelo
comando flatshot a partir do modelo apresentado na Figura 21.
Exerccio 5.1.1 Dena uma funo denominada prisma que cria um slido prism-
tico regular. A funo dever receber o nmero de lados do prisma, as coordenadas
tridimensionais do centro da base do prisma, a distncia do centro da base a cada
vrtice, o ngulo de rotao da base do prisma e as coordenadas tridimensionais do
centro do topo do prisma.
A ttulo de exemplo, considere as expresses
(prisma 3 (xyz 0 0 0) 0.4 0 (xyz 0 0 5))
(prisma 5 (xyz -2 0 0) 0.4 0 (xyz -1 1 5))
(prisma 4 (xyz 0 2 0) 0.4 0 (xyz 1 1 5))
(prisma 6 (xyz 2 0 0) 0.4 0 (xyz 1 -1 5))
(prisma 7 (xyz 0 -2 0) 0.4 0 (xyz -1 -1 5))
cuja avaliao produz a imagem seguinte:
77
5.2 Modelao de Colunas Dricas
A modelao tri-dimensional tem a virtude de nos permitir criar entidades
geomtricas muito mais realistas do que meros aglomerados de linhas a re-
presentarem vistas dessas entidades. A ttulo de exemplo, reconsideremos a
coluna Drica que apresentmos na seco 4.16. Nessa seco desenvolvemos
um conjunto de funes cuja invocao criava uma vista frontal dos compo-
nentes da coluna Drica. Apesar dessas vistas serem teis, ainda mais til
poder modelar directamente a coluna como uma entidade tri-dimensional.
Nesta seco vamos empregar algumas das operaes mais relevantes para
a modelao tri-dimensional de colunas, em particular, a criao de troncos
de cone para modelar o fuste e o coxim e a criao de paralelippedos para
modelar o baco.
Anteriormente, as nossas colunas estavam dispostas no plano x-y, com
as colunas a crescer ao longo do eixo dos y. Agora, ser apenas a base das
colunas que car assente no plano x-y: o corpo das colunas ir desenvolver-se
ao longo do eixo dos z. Embora fosse trivial empregar outro arranjo dos eixos
do sistema de coordenadas, este aquele que mais prximo da realidade.
semelhana de inmeras outras operaes do AutoCad, cada uma das
operaes de modelao de slidos do AutoCad permite vrios modos dife-
rentes de invocao. No caso da operao de modelao de troncos de cone
coneo modo que nos mais conveniente aquele em que a operao recebe
as coordenadas do centro da base do cone e o raio dessa base e, de seguida, es-
pecicamos o raio do topo do cone (com a opo Top radius) e, nalmente,
a altura do tronco.
Tendo isto em conta, podemos redenir a operao que constri o fuste tal
como se segue:
78
(defun fuste (p a-fuste r-base r-topo)
(command "_.cone" p r-base
"_t" r-topo a-fuste))
Do mesmo modo, a operao que constri o coxim car com a forma:
(defun coxim (p a-coxim r-base r-topo)
(command "_.cone" p r-base
"_t" r-topo a-coxim))
Finalmente, no que diz respeito ao bacoo paralelippedo que colocado
no topo da colunatemos vrias maneiras de o especicarmos. A mais directa
consiste em indicar os dois cantos do paralelippedo. Uma outra, menos di-
recta, consiste em indicar o centro do paralelippedo seguido do tamanho dos
seus lados. Por agora, vamos seguir a mais directa:
(defun abaco (p a-abaco l-abaco)
(command "_.box"
(+xyz p (/ l-abaco -2.0) (/ l-abaco -2.0) 0)
(+xyz p (/ l-abaco +2.0) (/ l-abaco +2.0) a-abaco)))
Exerccio 5.2.1 Implemente a funo abaco mas empregando a criao de um parale-
lippedo centrado num ponto seguido da especicao do seu comprimento, largura
e altura.
Finalmente, falta-nos implementar a funo coluna que, semelhana do
que fazia no caso bi-dimensional, invoca sucessivamente as funes fuste,
coxim e abaco mas, agora, elevando progressivamente a coordenada z:
(defun coluna (p
a-fuste r-base-fuste
a-coxim r-base-coxim
a-abaco l-abaco)
(fuste p a-fuste r-base-fuste r-base-coxim)
(coxim (+z p a-fuste) a-coxim r-base-coxim (/ l-abaco 2.0))
(abaco (+z p (+ a-fuste a-coxim)) a-abaco l-abaco))
Com estas redenies, podemos agora repetir as colunas que desenhmos
na seco 4.17 e que apresentmos na Figura 19, mas, agora, gerando uma
imagem tri-dimensional dessas mesmas colunas, tal como apresentamos na
Figura 23:
(coluna (xyz 0 0 0) 9 0.5 0.4 0.3 0.3 1.0)
(coluna (xyz 3 0 0) 7 0.5 0.4 0.6 0.6 1.6)
(coluna (xyz 6 0 0) 9 0.7 0.5 0.3 0.2 1.2)
(coluna (xyz 9 0 0) 8 0.4 0.3 0.2 0.3 1.0)
(coluna (xyz 12 0 0) 5 0.5 0.4 0.3 0.1 1.0)
(coluna (xyz 15 0 0) 6 0.8 0.3 0.2 0.4 1.4)
A partir deste modelo, agora trivial usarmos as capacidades do AutoCad
para extrair qualquer vista que pretendamos, incluindo perspectivas como a
que apresentamos na Figura 24.
79
Figura 23: Modelao tri-dimensional das variaes de colunas dricas.
Figura 24: Perspectiva da modelao tri-dimensional das variaes de colunas
dricas.
80
6 Expresses Condicionais
Existem muitas operaes cujo resultado depende da realizao de um de-
terminado teste. Por exemplo, a funo matemtica [x[que calcula o valor
absoluto de um nmeroequivale ao prprio nmero, se este positivo, ou
equivale ao seu simtrico se for negativo. Esta funo ter, portanto de testar
o seu argumento e escolher uma de duas alternativas: ou devolve o prprio
argumento, ou devolve o seu simtrico.
Estas expresses, cujo valor depende de um ou mais testes a realizar previ-
amente, permitindo escolher vias diferentes para a obteno do resultado, so
designadas expresses condicionais.
No caso mais simples de uma expresso condicional, existem apenas duas
alternativas a seguir. Isto implica que o teste que necessrio realizar para
determinar a via de clculo a seguir deve produzir um de dois valores, em que
cada valor designa uma das vias.
Seguindo o mesmo racioccio, uma expresso condicional com mais de
duas alternativas dever implicar um teste com igual nmero de possveis
resultados. Uma expresso da forma caso o valor do teste seja 1, 2 ou 3, o
valor da expresso 10, 20 ou 30, respectivamente um exemplo desta ca-
tegoria de expresses que existe nalgumas linguagens (Basic, por exemplo).
Contudo, estas expresses podem ser facilmente reduzidas primeira atravs
da decomposio da expresso condicional mltipla numa composio de ex-
presses condicionais simples, em que o teste original tambm decomposto
numa srie de testes simples. Assim, poderiamos transformar o exemplo an-
terior em: se o valor do teste 1, o resultado 10, caso contrrio, se o valor
2, o resultado 20, caso contrrio 30.
6.1 Expresses Lgicas
Desta forma, reduzimos todos os testes a expresses cujo valor pode ser ape-
nas um de dois, e a expresso condicional assume a forma de se . . . ento
. . . caso contrrio . . . . A expresso cujo valor usado para decidir se devemos
usar o ramo ento ou o ramo caso contrrio denomina-se expresso lgica e
caracteriza-se por o seu valor ser interpretado como verdade ou falso. Por exem-
plo, a expresso lgica (> x y) testa se o valor de x maior que o valor de y.
Se for, a expresso avalia para verdade, caso contrrio avalia para falso.
6.2 Valores Lgicos
Algumas linguagens de programao consideram a verdade e o falso como
dois elementos de um tipo especial de dados denominado lgico ou booleano.
35
Outras linguagens, como o Lisp, entendem que o facto de se considerar um
valor como verdadeiro ou falso no implica necessariamente que o valor tenha
de ser de um tipo de dados especial, mas apenas que a expresso condicional
considera alguns dos valores como representando o verdadeiro e os restantes
como o falso.
35
De George Boole, matemtico ingls e inventor da lgebra da verdade e do falso.
81
Em Lisp, as expresses condicionais consideram como falso um nico va-
lor. Esse valor representado por nil, o mesmo valor que usmos anterior-
mente para representar uma lista vazia. Qualquer outro valor diferente de nil
considerado como verdadeiro. Assim, do ponto de vista de uma expresso
condicional, o nmero 123, por exemplo, um valor verdadeiro. Contudo,
no faz muito sentido para o utilizador humano considerar um nmero como
verdadeiro ou falso, pelo que se introduziu uma constante na linguagem para
representar verdade. Essa constante representa-se por t. A lgica que se t
diferente de nil e se nil o nico valor que representa a falsidade, ento t
representa necessariamente a verdade.
6.3 Predicados
No caso mais usual, uma expresso lgica uma invocao de funo com
determinados argumentos. Nesta situao, a funo usada como teste de-
nominada predicado e o valor do teste interpretado como sendo verdadeiro
ou falso. O predicado , consequentemente, uma funo que devolve apenas
verdade ou falso.
Apesar da adopo dos smbolos t e nil, convm alertar que nem todos
os predicados devolvem t ou nil exclusivamente. Alguns h que, quando
querem indicar verdade, devolvem valores diferentes de t (e de nil, obvia-
mente).
6.4 Predicados Aritmticos
Os operadores relacionais matemticos <, >, =, , e ,= so um dos exemplos
mais simples de predicados. Estes operadores comparam nmeros entre si e
permitem saber se um nmero menor que outro. O seu uso em Lisp segue as
regras da notao prexa e escrevem-se, respectivamente, <, >, =, <=, >= e /=.
Eis alguns exemplos:
_$ (> 4 3)
t
_$ (< 4 3)
nil
_$ (<= (+ 2 3) (- 6 1))
t
6.5 Operadores Lgicos
Para se poder combinar expresses lgicas entre si existem os operadores and,
or e not. O and e o or recebem qualquer nmero de argumentos. O not s
recebe um. O valor das combinaes que empregam estes operadores lgicos
determinado do seguinte modo:
O and avalia os seus argumentos da esquerda para a direita at que um
deles seja falso, devolvendo este valor. Se nenhum for falso o and de-
volve verdade.
82
O or avalia os seus argumentos da esquerda para a direita at que um
deles seja verdade, devolvendo este valor. Se nenhum for verdade o or
devolve falso.
O not avalia para verdade se o seu argumento for falso e para falso em
caso contrrio.
Note-se que embora o signicado de falso seja claro pois corresponde ne-
cessariamente ao valor nil, o signicado de verdade j no to claro pois,
desde que seja diferente de nil, considerado verdade.
Exerccio 6.5.1 Qual o valor das seguintes expresses?
1. (and (or (> 2 3) (not (= 2 3))) (< 2 3))
2. (not (or (= 1 2) (= 2 3)))
3. (or (< 1 2) (= 1 2) (> 1 2))
4. (and 1 2 3)
5. (or 1 2 3)
6. (and nil 2 3)
7. (or nil nil 3)
6.6 Predicados com nmero varivel de argumentos
Uma propriedade importante dos predicados aritmticos <, >, =, <=, >= e
/= aceitarem qualquer nmero de argumentos. No caso em que h mais
do que um argumento, o predicado aplicado sequencialmente aos pares
de argumentos. Assim, (< e
1
e
2
e
3
... e
n1
e
n
) equivalente a escrever
(and (< e
1
e
2
) (< e
2
e
3
) ... (< e
n1
e
n
)). Este comportamento vis-
vel nos sequintes exemplos.
_$ (< 1 2 3)
T
_$ (< 1 2 2)
nil
Um caso particular que convm ter em ateno que embora a expres-
so (= e
1
e
2
... e
n
) teste se os elementos e
1
e
2
. . . e
n
so todos iguais,
(/= e
1
e
2
... e
n
) no testa se os elementos e
1
e
2
. . . e
n
so todos dife-
rentes: uma vez que o teste aplicado sucessivamente a pares de elementos
perfeitamente possvel que existam dois elementos iguais desde que no sejam
consecutivos. Esse comportamento visvel no seguinte exemplo:
36
_$ (/= 1 2 3)
T
_$ (/= 1 2 1)
T
36
Outros dialectos de Lisp apresentam um comportamento diferente para esta operao.
Em Common Lisp, por exemplo, o predicado /= testa se, de facto, os argumentos so todos
diferentes.
83
6.7 Predicados sobre Cadeias de Caracteres
Na verdade, os operadores <, >, =, <=, >= e /= no se limitam a operarem
sobre nmeros: eles aceitam tambm cadeias de caracteres como argumentos,
fazendo uma comparao lexicogrca: os argumentos so comparados carc-
ter a carcter enquanto forem iguais. Quando so diferentes, a ordem lxico-
graca do primeiro carcter diferente nas duas strings determina o valor lgico
da relao. Se a primeira string acabar antes da segunda, considera-se que
menor, caso contrrio, maior.
_$ (= "pois" "pois")
T
_$ (= "pois" "poisar")
nil
_$ (< "pois" "poisar")
T
_$ (< "abcd" "abce")
T
6.8 Predicados sobre Smbolos
Para alm de nmeros e strings, o predicado = permite ainda comparar smbo-
los.
_$ (= pois pois)
T
_$ (= pois poisar)
nil
Nenhum dos outros operadores relacionais aplicvel a smbolos.
6.9 Predicados sobre Listas
Vimos que os dados manipulados pelo Lisp se podiam classicar em atmicos
ou no-atmicos consoante era impossvel, ou no, aplicar-lhes as operaes
de listas car e cdr.
Para facilitar a identicao das entidades atmicos, a linguagem Lisp dis-
ponibiliza uma funo denominada atom que s verdadeira para as entida-
des atmicas:
_$ (atom 1)
T
_$ (atom "dois")
T
_$ (atom quatro)
T
_$ (atom (cons 1 "dois"))
nil
_$ (atom (list 1 "dois" 3.0))
nil
_$ (atom ())
84
T
_$ (atom t)
T
_$ (atom nil)
T
A funo atom permite-nos, assim, saber quais os tipos de entidades a que
podemos aplicar as operaes car e cdr: apenas aquelas que no so tomos.
6.10 Reconhecedores
Para alm dos operadores relacionais, existem muitos outros predicados em
Lisp, como por exemplo o zerop que testa se um nmero zero:
_$ (zerop 1)
nil
_$ (zerop 0)
t
O facto de zerop terminar com a letra p deve-se a uma conveno adop-
tada em Lisp segundo a qual os predicados cujo nome seja uma ou mais pala-
vras devem ser distinguidos das restantes funes atravs da concatenao da
letra p (de Predicate) ao seu nome. Infelizmente, por motivos histricos, nem
todos os predicados pr-denidos seguem esta conveno. No entanto, nos
predicados que denirmos devemos ter o cuidado de seguir esta conveno.
Note-se que o operador zerop serve para reconhecer umelemento empar-
ticular (o zero) de um tipo de dados (os nmeros). Este gnero de predicados
denominam-se de reconhecedores. Um outro exemplo de um reconhecedor o
predicado null que reconhece a lista vazia. A funo null devolve verdade
quando aplicada a uma lista vazia e falso em qualquer outro caso:
_$ (list 1 2 3)
(1 2 3)
_$ (null (list 1 2 3))
nil
_$ (list)
nil
_$ (null (list))
T
Para se perceberem as duas ltimas expresses do exemplo anterior con-
vm recordar que nil representa no s a falsidade mas tambm a lista vazia.
6.11 Reconhecedores Universais
Um outro conjunto importante de predicados so os denominados reconhece-
dores universais. Estes no reconhecem elementos particulares de um tipo de
dados mas sim todos os elementos de um particular tipo de dados. Um reco-
nhecedor universal aceita qualquer tipo de valor como argumento e devolve
verdade se o valor do tipo pretendido.
85
Por exemplo, para sabermos se uma determinada entidade um nmero
podemos empregar o predicado numberp:
37
_$ (numberp 1)
T
_$ (numberp nil)
nil
_$ (numberp "Dois")
nil
Para testar se uma determinada entidade uma lista podemos empregar o
predicado listp. Este predicado verdade para qualquer lista (incluindo a
lista vazia) e falso para tudo o resto:
_$ (listp (list 1 2))
T
_$ (listp 1)
nil
_$ (listp (list))
T
_$ (listp (cons 1 2))
T
Note-se, no ltimo exemplo, que o reconhecedor universal listp tambm
considera como lista um mero par de elementos. Na realidade, este reconhece-
dor devolve verdade sempre que o seu argumento um dotted pair ou o nil.
As listas, como vimos, no so mais do que arranjos particulares de dotted pairs
ou, no limite, uma lista vazia.
Para a maioria dos tipos, o Auto Lisp no providencia nenhum reconhe-
cedor universal, antes preferindo usar a funo genrica type que devolve o
nome do tipo como smbolo. Como vimos na secco 3.12, temos:
_$ (type pi)
REAL
_$ (type 1)
INT
_$ (type "Ola")
STR
_$ (type quadrado)
USUBR
_$ (type +)
SUBR
Obviamente, nada nos impede de denir os reconhecedores universais que
pretendermos. semelhana do predicado numberp podemos denir os seus
subcasos integerp e realp:
37
tradicional, em vrios dialectos de Lisp, terminar o nome dos predicados com a letra p.
Noutros dialectos, prefere-se terminar esse nome com um ponto de interrogao precisamente
porque, na prtica, a invocao de um predicado corresponde a uma pergunta que fazemos.
Neste texto, nos casos em que zer sentido enquadrarmo-nos com a tradio, iremos empregar
a letra p; em todos os outros casos iremos empregar o ponto de interrogao.
86
(defun integerp (obj)
(= (type obj) int))
(defun realp (obj)
(= (type obj) real))
igualmente trivial denir um reconhecedor universal de strings e outro
para funes (compiladas ou no):
(defun stringp (obj)
(= (type obj) str))
(defun functionp (obj)
(or (= (type obj) subr)
(= (type obj) usubr)))
6.12 Exerccios
Exerccio 6.12.1 O que uma expresso condicional? O que uma expresso lgica?
Exerccio 6.12.2 O que um valor lgico? Quais so os valores lgicos empregues em
Auto Lisp?
Exerccio 6.12.3 O que um predicado? D exemplos de predicados em Auto Lisp.
Exerccio 6.12.4 O que um operador relacional? D exemplos de operadores relaci-
onais em Auto Lisp.
Exerccio 6.12.5 O que um operador lgico? Quais so os operadores lgicos que
conhece em Auto Lisp?
Exerccio 6.12.6 O que um reconhecedor? O que um reconhecedor universal? D
exemplos em Auto Lisp.
Exerccio 6.12.7 Traduza para Lisp as seguintes expresses matemticas:
1. x < y
2. x y
3. x < y y < z
4. x < y x < z
5. x y z
6. x y < z
7. x < y z
87
7 Estruturas de Controle
At agora, temos visto essencialmente a denio e aplicao de funes. No
caso da aplicao de funes, vimos que o Lisp avalia todos os elementos da
combinao e, em seguida, invoca a funo que o resultado da avaliao do
primeiro elemento da combinao usando, como argumentos, o resultado da
avaliao dos restantes elementos. Este comportamento imposto pela lingua-
gem e um exemplo de uma estrutura de controle.
Em termos computacionais, o controle est associado ordem pela qual o
computador executa as instrues que lhe damos. Se nada for dito em contr-
rio, o computador executa sequencialmente as instrues que lhe damos. No
entanto, algumas dessas instrues podem provocar o salto de instrues, i.e.,
podem forar o computador a continuar a executar instrues mas a partir de
outro ponto do programa.
Com o tempo, os programadores aperceberam-se que a utilizao indiscri-
minada de saltos tornava os programas extremamente difceis de compreen-
der por um ser humano e, por isso, inventaram-se formas mais estruturadas
de controlar o computador: as estruturas de controle.
As estruturas de controle no so mais do que formas padronizadas de se
controlar um computador. Esta estruturas de controle no so disponibiliza-
das pelo computador em si mas sim pela linguagem de programao que es-
tivermos a utilizar que, depois, as converte nas estruturas de controle bsicas
do computador.
Iremos agora ver algumas das estruturas de controle mas importantes.
7.1 Sequenciao
A estrutura de controle mais simples que existe a sequenciao.
Na estrutura de controle de sequenciao, o Lisp avalia uma sequncia de
expresses uma a seguir outra, devolvendo o valor da ltima. Logicamente,
se apenas o valor da ltima expresso utilizado, ento os valores de todas as
outras avaliaes dessa sequncia so descartados e estas apenas so relevante
pelos efeitos secundrios que possam provocar.
Como j vimos, possvel usar sequenciao na denio de uma funo.
Esta funo, quando invocada, ir sucessivamente avaliar cada uma das ex-
presses, descartando o seu valor, at chegar ltima que ser avaliada e o
seu valor ser considerado como o valor da invocao da funo.
Aquando da denio da coluna drica, vimos que a funo coluna usava
sequenciao para desenhar, sucessivamente, o fuste, o coxim e o baco:
(defun coluna (p
a-fuste r-base-fuste
a-coxim r-base-coxim
a-abaco l-abaco)
(fuste p a-fuste r-base-fuste r-base-coxim)
(coxim (+z p a-fuste) a-coxim r-base-coxim (/ l-abaco 2.0))
(abaco (+z p (+ a-fuste a-coxim)) a-abaco l-abaco))
88
Como se pode ver, a funo recebe vrios parmetros necessrios para es-
pecicar completamente as caractersticas geomtricas da coluna.
Quando invocada, a funo coluna limita-se a, primeiro, invocar a fun-
o fuste, passando-lhe os argumentos relevantes, segundo, invocar a fun-
o coxim, passando-lhe os argumentos relevantes e, terceiro, invocar a fun-
o abaco, passando-lhe os argumentos relevantes. precisamente este pri-
meiro, segundo, terceiro que caracteriza a estrutura de controle de se-
quenciao: as avaliaes so feitas sequencialmente.
Se tivermos em conta que uma funo, quando invocada, precisa de com-
putar e devolver um valor, a presena de sequenciao levanta a pergunta so-
bre qual dos valores que foram sucessivamente computados que representa
o valor da funo invocada: por convenincia, Lisp arbitra que o ltimo e
todos os anteriores so descartados.
Embora o corpo de uma funo possa conter vrias expresses que, quando
a funo invocada, so avaliadas sequencialmente, na realidade, a sequenci-
ao implementada em Lisp atravs de um operador denominado progn:
_$ (progn
(+ 1 2)
(
*
3 4))
12
Este operador recebe vrias expresses como argumento que avalia se-
quencialmente, devolvendo o valor da ltima. Quando denimos uma fun-
o todas as expresses que colocamos no corpo da funo so avaliadas num
progn implcito. Como iremos ver, existem ainda outras formas da linguagem
Lisp que possuem progns implcitos.
38
7.2 Invocao de Funes
A invocao de uma funo a estrutura de controle mais usada em Lisp.
Para se invocar uma funo, necessrio construir uma combinao cujo
primeiro elemento seja uma expresso que avalia para a funo que se pre-
tende invocar e cujos restantes elementos so expresses que avaliam para os
argumentos que se pretende passar funo. O resultado da avaliao da
combinao o valor calculado pela funo para aqueles argumentos.
A avaliao de uma combinao deste gnero processa-se nos seguintes
passos:
1. Todos os elementos da combinao so avaliados, sendo que o valor do
primeiro elemento necessariamente uma funo.
38
O nome progn parece pouco intuitivo mas, como a maioria dos nomes usados em Lisp,
temuma histria que o justica. Os Lisps originais disponibilizavamumoperador denominado
prog (abreviatura de program) que, entre vrias outras coisas, permitia sequenciao. Para
alm deste operador, foram introduzidas variantes mais simples, denominadas prog1que
avaliava sequencialmente os seus argumentos e retornava o valor da primeira, prog2que
avaliava sequencialmente os seus argumentos e retornava o valor da segundae, nalmente,
prognque avaliava sequencialmente os seus argumentos e retornava o valor da ltima. Ape-
nas este ltimo operador foi implementado em Auto Lisp.
89
2. Associam-se os parmetros formais dessa funo aos argumentos, i.e.,
aos valores dos restantes elementos da combinao. Cada parmetro
associado a um argumento, de acordo com a ordem dos parmetros e
argumentos. gerado um erro sempre que o nmero de parmetros no
igual ao nmero de argumentos.
3. Avalia-se o corpo da funo tendo em conta estas associaes entre os
parmetros e os argumentos.
Para exemplicar, consideremos a denio da funo quadrado e a se-
guinte combinao:
_$ (defun quadrado (x) (
*
x x))
QUADRADO
_$ (+ 1 (quadrado 2) 3)
Para que o avaliador de Lisp consiga avaliar a ltima combinao neces-
sita de comear por avaliar todos os seus elementos. O primeiro, o smbolo
+, avalia para o procedimento que realiza somas mas, antes de poder fazer a
soma, precisa de determinar os seus argumentos atravs da avaliao dos res-
tantes elementos da combinao. O primeiro argumento o nmero 1 pois,
como vimos anteriormente, o valor de um nmero o prprio nmero. De-
pois de avaliar o primeiro argumento, o avaliador depara-se com uma nova
combinao. Nesse momento, suspende a avaliao que estava a fazer e inicia
uma nova avaliao, agora para a combinao (quadrado 2). Novamente,
porque se trata da aplicao de uma funo, o avaliador vai avaliar todos os
seus argumentos que, neste caso, apenas um nmero que avalia para ele pr-
prio. A partir deste momento, o controle transferido para o corpo da funo
quadrado, mas fazendo a associao do parmetro x ao valor 2. A avaliao
do corpo da funo quadrado implica a avaliao da combinao (
*
x x).
Trata-se de uma multiplicao cujos argumentos so obtidos pela repetida ava-
liao do smbolo x. Uma vez que a invocao da funo tinha associado x ao
argumento 2, o valor de x 2. No entanto, para realizar a multiplicao
necessrio ter em conta que se trata, mais uma vez, da invocao de uma fun-
o, pelo que a avaliao da invocao da funo quadrado por sua vez
suspensa para se passar avaliao da multiplicao. No instante seguinte, a
multiplicao realizada e tem como resultado o nmero 4. Nesse momento,
o avaliador termina a invocao da multiplicao e faz o controle regressar
avaliao do quadrado de 2. Uma vez que a multiplicao a ltima expresso
da funo quadrado, esta invocao vai tambm terminar tendo como resul-
tado o mesmo da multiplicao, i.e., 4. Mais uma vez, o avaliador vai transferir
o controle, agora para a expresso que estava a avaliar quando invocou a fun-
o quadrado, avaliando o ltimo argumento da soma (que avalia para ele
prprio), permitindo-lhe assim concluir a soma com o valor 8.
Resumidamente, a invocao de funes consiste em suspender a avali-
ao que se estava a fazer para (1) se associarem os argumentos da invocao
aos parmetros da funo invocada, (2) avaliar o corpo da funo tendo aquela
associao em conta e (3) retomar a avaliao suspendida usando como va-
lor da invocao o valor da ltima expresso do corpo da funo invocada.
90
As caractersticas da linguagem Lisp tornam-na particularmente apta de-
nio e invocao de funes. De facto, as bases matemticas da lingua-
gem Lisp assentam precisamente sobre o conceito de funo. Em Lisp, as
funes usam-se no s por uma questo de convenincia mas tambm por
uma questo de modelao: uma funo representa algo que devemos tornar
claro. O exemplo anterior pode ser reescrito para a forma (+ 1 (
*
2 2) 3)
mas perdeu-se o conceito de quadrado que estava anteriormente evidente.
Em geral, quando usamos uma funo estamos a exprimir uma dependn-
cia entre entidades. Uma dessas entidades diz-se ento funo das restantes e o
seu valor determinado pela invocao de uma funo que recebe as restantes
entidades como argumentos.
7.3 Variveis Locais
Consideremos a equao do segundo grau
ax
2
+ bx + c = 0
Como sabemos, esta equao tem duas razes que se podem obter pela famosa
frmula resolvente:
x =
b +

b
2
4ac
2a
x =
b

b
2
4ac
2a
Dada a utilidade desta frmula, podemos estar interessados em denir
uma funo que, dados os coecientes a, b e c da equao do segundo grau
nos devolve as suas duas raizes. Para isso, vamos devolver um par de nme-
ros calculados usando as duas frmulas acima:
(defun raizes-equacao-segundo-grau (a b c)
(cons (/ (- (- b)
(sqrt (- (quadrado b) (
*
4 a c))))
(
*
2 a))
(/ (+ (- b)
(sqrt (- (quadrado b) (
*
4 a c))))
(
*
2 a))))
Usando a denio anterior, podemos agora calcular as solues da equa-
o (x 2)(x 3) = 0. De facto, esta equao equivalente a x
2
5x + 6 = 0,
i.e., basta calcularmos as razes empregando a frmula resolvente com os coe-
cientes a = 1, b = 5, c = 6, ou seja:
_$ (raizes-equacao-segundo-grau 1 -5 6)
(2.0 . 3.0)
Aparentemente, tudo est bem. Contudo, h uma inecincia bvia: a
funo raizes-equacao-segundo-grau calcula duas vezes o mesmo va-
lor correspondente ao termo

b
2
4ac. Isso perfeitamente visvel na dupla
ocorrncia da expresso (sqrt (- (quadrado b) (
*
4 a c))).
91
Para resolver este problema, o Auto Lisp permite a utilizao de variveis
locais. Estas so variveis em tudo semelhantes aos parmetros das funes
mas com a diferena de no receberem argumento correspondente na invoca-
o da funo cando automaticamente com o valor nil. Logicamente, para
que sejam teis, devemos mudar o seu valor para algo que nos interesse.
Para se indicar que uma funo vai usar variveis locais, estas tm de ser
declaradas juntamente com a lista de parmetros da funo. Vamos agora am-
pliar a sintaxe da denio de funes que apresentmos anteriormente (na
seco 3.4 de modo a incorporar a declarao de variveis locais:
(defun nome (parmetro
1
... parmetro
n
/ varivel
1
... varivel
m
)
corpo)
Note-se que as variveis locais so separadas dos parmetros por uma
barra. necessrio ter o cuidado de no colar a barra nem ao ltimo pa-
rmetro nem primeira varivel sob pena de o Auto Lisp considerar a barra
como parte de um dos nomes (e, consequentemente, tratar as variveis locais
como se de parmetros se tratasse).
Embora seja raro, perfeitamente possvel termos funes sem parmetros
mas com variveis locais. Neste caso, a sintaxe da funo seria simplesmente:
(defun nome (/ varivel
1
... varivel
m
)
corpo)
7.4 Atribuio
Para alm da declarao de uma varivel local ainda necessrio atribuir-lhe
um valor, i.e., realizar uma operao de atribuio. Para isso, o Auto Lisp dis-
ponibiliza o operador setq, cuja sintaxe :
(setq varivel
1
expresso
1
...
varivel
m
expresso
m
)
A semntica deste operador consiste simplesmente em avaliar a expresso
expresso
1
e associar o seu valor ao nome varivel
1
, repetindo este pro-
cesso para todas as restantes variveis e valores.
atravs do uso de variveis locais e do operador setq que vamos sim-
plicar a funo raizes-equacao-segundo-grau e, simultaneamente, va-
mos torn-la mais eciente. Para isso, basta-nos calcular o valor de

b
2
4ac,
associando-o a uma varivel local e, em seguida, usamos esse valor nos dois
locais em que necessrio. Do mesmo modo, podemos declarar uma varivel
para conter o valor da expresso 2a e outra para conter b. O resultado ca
ento:
(defun raizes-equacao-segundo-grau (a b c
/ raiz-b2-4ac 2a -b)
(setq raiz-b2-4ac (sqrt (- (quadrado b) (
*
4 a c)))
92
2a (
*
2 a)
-b (- b))
(cons (/ (- -b raiz-b2-4ac)
2a)
(/ (+ -b raiz-b2-4ac)
2a)))
importante salientar que raiz-b2-4ac, 2a e -b so apenas nomes asso-
ciados a nmeros que resultaram da avaliao das expresses corresponden-
tes. Aps estas atribuies, quando se vai avaliar a expresso que constri o
par, esses nomes vo ser por sua vez avaliados e, logicamente, vo ter como
valor a atribuio que lhes tiver sido feita anteriormente.
Um outro ponto importante a salientar que aqueles nomes s existem
durante a invocao da funo e, na realidade, existem diferentes ocorrncias
daqueles nomes para diferentes invocaes da funo. Este ponto de crucial
importncia para se perceber que, aps a invocao da funo, os nomes, quer
de parmetros, quer de variveis locais, desaparecem, conjuntamente com as
associaes que lhes foram feitas.
Exerccio 7.4.1 Como viu, as variveis locais permitemevitar clculos repetidos. Uma
outra forma de evitar esses clculos repetidos atravs do uso de funes auxiliares.
Redena a funo raizes-equacao-segundo-grau de forma a que no seja ne-
cessrio usar quaisquer variveis locais.
7.5 Variveis Globais
Qualquer referncia a um nome que no est declarado localmente implica
que esse nome seja tratado como uma varivel global.
39
O nome pi, por exem-
plo, representa a varivel pi e pode ser usado em qualquer ponto dos nossos
programas. Por esse motivo, o nome pi designa uma varivel global.
A declarao de variveis globais mais simples que a das variveis lo-
cais: basta uma primeira atribuio, em qualquer ponto do programa, para
a varivel car automaticamente declarada. Assim, se quisermos introduzir
uma nova varivel global, por exemplo, para denir a razo de ouro
40
=
1 +

5
2
1.6180339887
basta-nos escrever:
39
Na realidade, o Auto Lisp permite ainda uma terceira categoria de nomes que no so nem
locais, nem globais. Mais frente discutiremos esse caso.
40
Tambm conhecida por proporo divina e nmero de ouro, entre outras designaes, e abre-
viada por em homenagem a Fineas, escultor Grego que foi responsvel pela construo do
Partnon onde, supostamente, usou esta proporo. A razo de ouro foi inicialmente intro-
duzida por Euclides quando resolveu o problema de dividir um segmento de recta em duas
partes de tal forma que a razo entre o segmento de recta e a parte maior fosse igual razo
entre a parte maior e a menor. Se for a o comprimento do parte maior e b o da menor, o pro-
blema de Euclides idntico a dizer que
a+b
a
=
a
b
. Daqui resulta que a
2
ab b
2
= 0 ou que
a =
b

b
2
+4b
2
2
= b
1

5
2
. A raiz que faz sentido , obviamente, a = b
1+

5
2
e, consequente-
mente, a razo de ouro =
a
b
=
1+

5
2
.
93
(setq razao-de-ouro (/ (+ 1 (sqrt 5)) 2))
A partir desse momento, o nome razao-de-ouro pode ser referenciado
em qualquer ponto dos programas.
importante referir que o uso de variveis globais deve ser restrito, na
medida do possvel, denio de constantes, i.e., variveis cujo valor nunca
muda como, por exemplo, pi. Outros exemplos que podem vir a ser teis in-
cluem2
*
pi, pi/2, 4
*
pi e pi/4, bemcomo os seus simtricos, que se denem
custa de:
(setq 2
*
pi (
*
2 pi))
(setq pi/2 (/ pi 2))
(setq 4
*
pi (
*
4 pi))
(setq pi/4 (/ pi 4))
(setq -pi (- pi))
(setq -2
*
pi (- 2
*
pi))
(setq -pi/2 (- pi/2))
(setq -4
*
pi (- 4
*
pi))
(setq -pi/4 (- pi/4))
O facto de uma varivel global ser uma constante implica que a varivel
atribuda uma nica vez, no momento da sua denio. Esse facto permite-
nos usar a varivel sabendo sempre qual o valor a que ela est associada.
Infelizmente, por vezes necessrio usarmos variveis globais que no so
constantes, i.e., o seu valor muda durante a execuo do programa, por aco
de diferentes atribuies feitas em locais diferentes e em momentos diferen-
tes. Quando temos variveis globais que so atribuidas em diversos pontos do
nosso programa, o comportamento deste pode tornar-se muito mais difcil de
entender pois, na prtica, pode ser necessrio compreender o funcionamento
de todo o programa em simultneo e no apenas funo a funo, como temos
feito. Por este motivo, devemos evitar o uso de variveis globais que sejam
atribuidas em vrios pontos do programa.
7.6 Variveis Indenidas
A linguagem Auto Lisp difere da maioria dos outros dialecto de Lisp no tra-
tamento que d a variveis indenidas, i.e., variveis a que nunca foi atribudo
um valor.
41
Em geral, as linguagens de programao consideram que a avalia-
o de uma varivel indenida um erro. No caso da linguagem Auto Lisp, a
avaliao de qualquer varivel indenida simplesmente nil.
41
Na terminologia original do Lisp, estas variveis diziam-se unbound.
94
A consequncia deste comportamento que existe o potencial de os er-
ros tipogrcos passarem despercebidos, tal como demonstrado no seguinte
exemplo:
_$ (setq minha-lista (list 1 2 3))
(1 2 3)
_$ (cons 0 mimha-lista)
(0)
Reparemos, no exemplo anterior, que a varivel que foi denida no a
mesma que est a ser avaliada pois a segunda tem uma gralha no nome. Em
consequncia, a expresso que tenta juntar o 0 ao nicio da lista (1 2 3) est,
na realidade, a juntar o 0 ao nicio da lista nil que, como sabemos, tambm
a lista vazia.
Este gnero de erros pode ser extremamente difcil de detectar e, por isso,
a maioria das linguagens abandonou este comportamento. O Auto Lisp, por
motivos histricos, manteve-o, o que nos obriga a termos de ter muito cuidado
para no cometermos erros que depois passem indetectados.
7.7 Propores de Vitrvio
A modelao de colunas dricas que desenvolvemos na seco 5.2 permite-
nos facilmente construir colunas, bastando para isso indicarmos os valores dos
parmetros relevantes, como a altura e o raio da base do fuste, a altura e raio
da base do coxim e a altura e largura do baco. Cada um destes parmetros
constitui um grau de liberdade que podemos fazer variar livremente.
Embora seja lgico pensar que quantos mais graus de liberdade tivermos
mais exvel a modelao, a verdade que um nmero excessivo de par-
metros pode conduzir a modelos pouco realistas. Esse fenmeno evidente na
Figura 25 onde mostramos uma perspectiva de um conjunto de colunas cujos
parmetros foram escolhidos aleatoriamente.
Na verdade, de acordo com os cnones da Ordem Drica, os diversos pa-
rmetros que regulam a forma de uma coluna devem relacionar-se entre si
segundo um conjunto de propores bem denidas. Vitrvio
42
, no seu famoso
tratado de arquitectura, descreveu essas propores em termos do conceito de
mdulo:
43
42
Vitrvio foi um escritor, arquitecto e engenheiro romano que viveu no sculo um antes de
Cristo e autor do nico tratado de arquitectura que sobreviveu a antiguidade.
43
As propores da ordem Drica derivam das propores do prprio ser humano. Segundo
Vitrvio,
Uma vez que pretendiam erguer um templo com colunas mas no tinham
conhecimento das propores adequadas, [] mediram o comprimento dum p
de um homem e viram que era um sexto da sua altura e deram coluna uma
proporo semelhante, i.e., zeram a sua altura, incluindo o capitel, seis vezes a
largura da coluna medida na base. Assim, a ordem Drica obteve a sua proporo
e a sua beleza, da gura masculina.
95
Figura 25: Perspectiva da modelao tri-dimensional de colunas cujos par-
metros foram escolhidos aleatoriamente. Apenas uma das colunas obedece
aos cnones da Ordem Drica.
A largura das colunas, na base, ser de dois modulos e a sua altura, incluindo
os capitis, ser de catorze.
Daqui se deduz ummdulo iguala o raio da base da coluna e que a altura
da coluna dever ser 14 vezes esse raio. Dito de outra forma, o raio da
base da coluna dever ser
1
14
da altura da coluna.
A altura do capitel ser de um mdulo e a sua largura de dois mdulos e um
sexto.
Isto implica que a altura do coxim somado do baco ser um mdulo,
ou seja, igual ao raio da base da coluna e a largura do baco ser de 2
1
6
mdulos ou
13
6
do raio. Juntamente com o facto de a altura da coluna
ser de 14 mdulos, implica ainda que a altura do fuste ser de 13 vezes o
raio.
Seja a altura do capitel dividida em trs partes, das quais uma formar o baco
com o seu cimteo, o segundo o quino (coxim) com os seus aneis e o terceiro o
pescoo.
Isto quer dizer que o baco tem uma altura de um tero de um modulo,
ou seja
1
3
do raio da base, e o coxim ter os restantes dois teros, ou seja,
2
3
do raio da base.
Estas consideraes levam-nos a poder determinar o valor de alguns dos
parmetros de desenho das colunas dricas em termos do raio da base do
fuste. Em termos de implementao, isso quer dizer que os parmetros da
funo passam a ser variveis locais cuja atribuio feita aplicando as pro-
96
Figura 26: Variaes de colunas dricas segundo as propores de Vitrvio.
pores estabelecidas por Vitrvio ao parmetro r-base-fuste. A denio
da funo ca ento:
(defun coluna (p
r-base-fuste r-base-coxim
/ a-fuste a-coxim a-abaco l-abaco)
(setq a-fuste (
*
13 r-base-fuste)
a-coxim (
*
(/ 2.0 3) r-base-fuste)
a-abaco (
*
(/ 1.0 3) r-base-fuste)
l-abaco (
*
(/ 13.0 6) r-base-fuste))
(fuste p a-fuste r-base-fuste r-base-coxim)
(coxim (+z p a-fuste) a-coxim r-base-coxim (/ l-abaco 2.0))
(abaco (+z p (+ a-fuste a-coxim)) a-abaco l-abaco))
Usando esta funo j possvel desenhar colunas que se aproximam mais
do padro drico (tal como estabelecido por Vitrvio).
44
AFigura 26 apresenta
as colunas desenhadas pelas seguintes invocaes:
(coluna (xyz 0 0 0) 0.3 0.2)
(coluna (xyz 3 0 0) 0.5 0.3)
(coluna (xyz 6 0 0) 0.4 0.2)
(coluna (xyz 9 0 0) 0.5 0.4)
(coluna (xyz 12 0 0) 0.5 0.5)
(coluna (xyz 15 0 0) 0.4 0.7)
7.8 Seleco
As propores de Vitrvio permitiram-nos reduzir o nmero de parmetros
independentes de uma coluna Drica a apenas dois: o raio da base do fuste e
44
A Ordem Drica estabelece ainda mais uma relao entre os parmetros das colunas, rela-
o essa que s iremos implementar na seco 7.10.
97
o raio da base do coxim. Contudo, no parece correcto que estes parmetros
sejam totalmente independentes pois isso permite construir colunas aberran-
tes em que o topo do fuste mais largo do que a base, tal como acontece com
a coluna a mais direita na Figura 26.
Na verdade, a caracterizao da OrdemDrica que apresentmos encontra-
se incompleta pois, acerca das propores das colunas, Vitrvio armou ainda
que:
. . . se uma coluna tem quinze ps ou menos, divida-se a largura
na base em seis partes e usem-se cinco dessas partes para formar
a largura no topo, . . . [Vitrvio, Os Dez Livros da Arquitectura,
Livro III, Cap. 3.1]
At agora, fomos capazes de traduzir para Auto Lisp todas as regras que
fomos anunciando mas, desta vez, a traduo levanta-nos uma nova dicul-
dade: como traduzir um termo da forma se, ento?
O termo se, ento permite-nos executar uma aco dependendo de uma
determinada condio ser verdadeira ou falsa: se uma coluna tem quinze ps
ou menos, ento o topo da coluna tem
5
6
da base, caso contrrio, . . . . Na lingua-
gem Lisp, estes termos descrevem uma forma de actuao que se denomina de
estrutura de controle de seleco. A seleco permite-nos escolher uma via de
aco mas apenas se uma determinada condio for verdadeira.
A estrutura de controle de seleco mais sosticada que a sequenciao.
Ela baseia-se na utilizao de expresses condicionais para decidir qual a pr-
xima expresso a avaliar. A forma mais simples desta estrutura de controle
o if cuja sintaxe a seguinte:
(if expresso condicional
expresso consequente
expresso alternativa)
O valor de uma combinao cujo primeiro elemento o if obtido da
seguinte forma:
1. A expresso condicional avaliada.
2. Se o valor obtido da avaliao anterior verdade, o valor da combinao
o valor da expresso consequente.
3. Caso contrrio, o valor obtido da avaliao anterior falso e o valor da
combinao o valor da expresso alternativa.
Este comportamento pode ser conrmado pelos seguintes exemplos:
_$ (if (> 3 2)
1
2)
1
_$ (if (> 3 4)
1
2)
2
98
Usando o if podemos denir funes cujo comportamento depende de
uma ou mais condies. Por exemplo, consideremos a funo max que recebe
dois nmeros como argumentos e devolve o maior deles. Para denirmos
esta funo apenas precisamos de testar se o primeiro argumento maior que
o segundo. Se for, a funo devolve o primeiro argumento, caso contrrio
devolve o segundo. Com base neste raciocnio, podemos escrever:
(defun max (x y)
(if (> x y)
x
y))
Muitas outras funes podem ser denidas custa do if. Por exemplo,
para calcularmos o valor absoluto de um nmero x, [x[, temos de saber se ele
negativo. Se for, o seu valor absoluto o seu simtrico, caso contrrio ele
prprio. Eis a denio:
(defun abs (x)
(if (< x 0)
(- x)
x))
Um outro exemplo mais interessante ocorre com a funo matemtica sinal
sgn, tambm conhecida como funo signum (sinal, em Latim). Esta funo
pode ser vista como a funo dual da funo valor absoluto pois tem-se sempre
x = sgn(x)[x[. A funo sinal denida por
sgnx =

1 se x < 0
0 se x = 0
1 caso contrrio
Quando denimos esta funo emLisp notamos que necessrio empregar
mais do que um if:
(defun signum (x)
(if (< x 0)
-1
(if (= x 0)
0
1)))
7.9 Seleco MltiplaA Forma cond
Quando uma denio de funo necessita de vrios ifs encadeados, nor-
mal que o cdigo comece a car mais difcil de ler. Neste caso, prefervel
usar uma outra forma que torna a denio da funo mais legvel. Para evi-
tar muitos ifs encadeados o Lisp providencia uma outra forma denominada
cond cuja sintaxe a seguinte:
99
(cond (expr
0,0
expr
0,1
... expr
0,n
)
(expr
1,0
expr
1,1
... expr
1,m
)
...
(expr
k,0
expr
k,1
... expr
k,p
))
O cond aceita qualquer nmero de argumentos. Cada argumento uma
lista de expresses denominada de clusula. A semntica do cond consiste
em avaliar sequencialmente a primeira expresso expr
i,0
de cada clusula at
encontrar uma cujo valor seja verdade. Nesse momento, o cond avalia todas as
restantes expresses dessa clusula e devolve o valor da ltima. Se nenhuma
das clusulas tiver uma primeira expresso que avalie para verdade, o cond
devolve nil. Se a clusula cuja primeira expresso verdade no contiver
mais expresses, o cond devolve o valor dessa primeira expresso.
importante perceber que os parntesis que envolvem as clusulas no
correspondem a nenhuma combinao: eles simplesmente fazem parte da sin-
taxe do cond e so necessrios para separar as clusulas umas das outras.
A pragmtica usual para a escrita de um cond (em especial quando cada
clusula contm apenas duas expresses) consiste em alinhar as expresses
umas debaixo das outras.
Usando o cond, a funo sinal pode ser escrita de forma mais simples:
(defun signum (x)
(cond ((< x 0)
-1)
((= x 0)
0)
(t
1)))
Note-se, no exemplo anterior, que a ltima clusula do cond tem, como ex-
presso lgica, o smbolo t. Como j vimos, este smbolo representa a verdade
pelo que a sua presena garante que ela ser avaliada no caso de nenhuma
das clusulas anteriores o ter sido. Neste sentido, clusula da forma (t ...)
representa um em ltimo caso . . . .
Exerccio 7.9.1 Qual o signicado de (cond (expr1 expr2))?
Exerccio 7.9.2 Qual o signicado de (cond (expr1) (expr2))?
A forma cond no estritamente necessria na linguagem pois possvel
fazer exactamente o mesmo comuma combinao entre formas if encadeadas
e formas progn, tal como a seguinte equivalncia o demonstra:
(cond (expr
0,0
expr
0,1
... expr
0,n
)
(expr
1,0
expr
1,1
... expr
1,m
)
.
.
.
(expr
k,0
expr
k,1
... expr
k,p
))

100
(if expr
0,0
(progn
expr
0,1
... expr
0,n
)
(if expr
1,0
(progn
expr
1,1
... expr
1,m
)
.
.
.
(if expr
k,0
(progn
expr
k,1
... expr
k,p
)
nil)))
Contudo, pragmaticamente falando, a forma cond pode simplicar subs-
tancialmente o programa quando o nmero de if encadeados maior que um
ou dois ou quando se pretende usar sequenciao no consequente ou alterna-
tiva do if.
Exerccio 7.9.3 Dena uma funo soma-maiores que recebe trs nmeros como
argumento e determina a soma dos dois maiores.
Exerccio 7.9.4 Dena a funo max3 que recebe trs nmeros como argumento e cal-
cula o maior entre eles.
7.10 Seleco nas Propores de Vitrvio
Uma vez compreendida a estrutura de controle de seleco, estamos em con-
dies de implementar a ltima regra de Vitrvio sobre as propores das co-
lunas da Ordem Drica. A regra arma que:
A diminuio no topo de uma coluna parece ser regulada se-
gundo os seguintes princpios: se uma coluna tem quinze ps ou
menos, divida-se a largura na base em seis partes e usem-se cinco
dessas partes para formar a largura no topo. Se a coluna tem en-
tre quinze e vinte ps, divida-se a largura na base em seis partes e
meio e usem-se cinco e meio dessas partes para a largura no topo
da coluna. Se a coluna tem entre vinte e trinta ps, divida-se a lar-
gura na base em sete partes e faa-se o topo diminuido medir seis
delas. Uma coluna de trinta a quarenta ps deve ser dividida na
base em sete partes e meia e, no princpio da diminuio, deve ter
seis partes e meia no topo. Colunas de quarenta a cinquenta ps de-
vem ser divididas em oito partes e diminuidas para sete delas no
topo da coluna debaixo do capitel. No caso de colunas mais altas,
determine-se proporcionalmente a diminuio com base nos mes-
mos princpios. [Vitrvio, Os Dez Livros da Arquitectura, Livro III,
Cap. 3.1]
Estas consideraes de Vitrvio permitem-nos determinar a razo entre o
topo e a base de uma coluna em funo da sua altura em ps.
45
45
O p foi a unidade fundamental de medida durante inmeros sculos mas a sua real di-
menso variou ao longo do tempo. O comprimento do p internacional de 304.8 milmetros
101
Consideremos ento a denio de uma funo, que iremos denominar de
raio-topo-fuste, que recebe como parmetros a largura da base da coluna
e a altura da coluna e devolve como resultado a largura do topo da coluna.
Uma traduo literal das consideraes de Vitrvio para Lisp permite-nos
comear por escrever:
(defun raio-topo-fuste (raio-base altura)
(cond ((<= altura 15) (
*
(/ 5.0 6.0) raio-base))
...))
O fragmento anterior corresponde, obviamente, armao: se uma coluna
tem quinze ps ou menos, divida-se a largura na base em seis partes e usem-se cinco
dessas partes para formar a largura no topo. No caso de a coluna no ter quinze
ps ou menos, ento passamos ao caso seguinte: se a coluna tem entre quinze
e vinte ps, divida-se a largura na base em seis partes e meio e usem-se cinco e meio
dessas partes para a largura no topo da coluna. A traduo deste segundo caso
permite-nos escrever:
(defun raio-topo-fuste (raio-base altura)
(cond ((<= altura 15) (
*
(/ 5.0 6.0) raio-base))
((and (> altura 15)
(<= altura 20)) (
*
(/ 5.5 6.5) raio-base))
...))
Uma anlise cuidadosa das duas clusulas anteriores mostra que, na rea-
lidade, estamos a fazer testes a mais na segunda clusula. De facto, se con-
seguimos chegar segunda clusula porque a primeira falsa, i.e., a altura
maior do que 15. Nesse caso, intil estar a testar novamente se a altura
maior do que 15. Assim, podemos simplicar a funo e escrever:
(defun raio-topo-fuste (raio-base altura)
(cond ((<= altura 15) (
*
(/ 5.0 6.0) raio-base))
((<= altura 20) (
*
(/ 5.5 6.5) raio-base))
...))
A continuao da traduo levar-nos-, ento, a:
(defun raio-topo-fuste (raio-base altura)
(cond ((<= altura 15) (
*
(/ 5.0 6.0) raio-base))
((<= altura 20) (
*
(/ 5.5 6.5) raio-base))
((<= altura 30) (
*
(/ 6.0 7.0) raio-base))
((<= altura 40) (
*
(/ 6.5 7.5) raio-base))
((<= altura 50) (
*
(/ 7.0 8.0) raio-base))
...))
O problema agora que Vitrvio deixou a porta aberta para colunas ar-
bitrariamente altas, dizendo simplesmente que no caso de colunas mais altas,
e foi estabelecido por acordo em 1958. Antes disso, vrios outros comprimentos foram usados,
como o p Drico de 324 milmetros, os ps Jnico e Romano de 296 milmetros, o p Ateniense
de 315 milmetros, os ps Egpcio e Fencio de 300 milmetros, etc.
102
determine-se proporcionalmente a diminuio com base nos mesmos princpios. Para
percebermos claramente de que princpios estamos a falar, consideremos a
evoluo da relao entre o topo e a base das colunas que visvel na ima-
gem lateral.
0
5
6
15
5
1
2
6
1
2
20
6
7
30
6
1
2
7
1
2
40
7
8
50
Arazo entre o raio do topo da coluna e o raio da base da coluna , tal como
se pode ver na margem(e j era possvel deduzir da funo raio-topo-fuste),
uma sucesso da forma
5
6
,
5
1
2
6
1
2
,
6
7
,
6
1
2
7
1
2
,
7
8
,
Torna-se agora bvio que, para colunas mais altas, os mesmos princpios
de que Vitrvio fala se resumem a, para cada 10 ps adicionais, somar
1
2
quer
ao numerador, quer ao denominador. No entanto, importante reparar que
este princpio s pode ser aplicado a partir dos 15 ps de altura pois o pri-
meiro intervalo maior que os restantes. Assim, temos de tratar de forma
diferente as colunas at aos 15 ps e, da para a frente, basta subtrair 20 ps
altura e determinar a diviso inteira por 10 para saber o nmero de vezes que
precisamos de somar
1
2
quer ao numerador quer ao denominador de
6
7
.
este tratar de forma diferente um caso e outro que, mais uma vez, su-
gere a necessidade de utilizao de uma estrutura de controle de seleco:
necessrio distinguir dois casos e reagir em conformidade para cada um. No
caso da coluna de Vitrvio, se a coluna tem uma altura a at 15 ps, a razo
entre o topo e a base r =
5
6
; se a altura a superior a 15 ps, a razo r entre o
topo e a base ser:
r =
6 +
a20
10
|
1
2
7 +
a20
10
|
1
2
A ttulo de exemplo, consideremos uma coluna com 43 ps de altura. A
diviso inteira de 43 20 por 10 2 portanto temos de somar 2
1
2
= 1 ao
numerador e denominador de
6
7
, obtendo
7
8
= 0.875.
Para um segundo exemplo nos limites do absurdo, consideremos uma co-
luna da altura do Empire State Building, i.e., com 449 metros de altura. Um
p, na ordem Drica, media 324 milmetros pelo que em 449 metros existem
449/0.324 1386 ps. A diviso inteira de 1386 20 por 10 136. A razo en-
tre o topo e a base desta hipottica coluna ser ento de
6+136/2
7+136/2
=
74
75
= 0.987.
Este valor, por ser muito prximo da unidade, mostra que a coluna seria pra-
ticamente cilndrica.
Com base nestas consideraes, podemos agora denir uma funo que,
dado um nmero inteiro representando a altura da coluna em ps, calcula a
razo entre o topo e a base da coluna. Antes, contudo, convm simplicar a
frmula para as colunas com altura superior a 15 ps. Assim,
r =
6 +
a20
10
|
1
2
7 +
a20
10
|
1
2
=
12 +
a20
10
|
14 +
a20
10
|
=
12 +
a
10
| 2
14 +
a
10
| 2
=
10 +
a
10
|
12 +
a
10
|
A denio da funo ca ento:
(defun raio-topo-fuste (raio-base altura / divisoes)
(setq divisoes (fix (/ altura 10)))
103
(if (<= altura 15)
(
*
(/ 5.0 6.0)
raio-base)
(
*
(/ (+ 10.0 divisoes)
(+ 12.0 divisoes))
raio-base)))
Esta a ltima relao que nos falta para especicarmos completamente
o desenho de uma coluna drica de acordo com as propores referidas por
Vitrvio no seu tratado de arquitectura. Vamos considerar, para este desenho,
que vamos fornecer as coordenadas do centro da base da coluna e a sua al-
tura. Todos os restantes parmetros sero calculados em termos destes. Eis a
denio da funo:
(defun coluna-dorica (p altura /
a-fuste r-base-fuste
a-coxim r-base-coxim
a-abaco l-abaco)
(setq r-base-fuste (/ altura 14.0)
r-base-coxim (raio-topo-fuste r-base-fuste altura)
a-fuste (
*
13.0 r-base-fuste)
a-coxim (
*
(/ 2.0 3) r-base-fuste)
a-abaco (
*
(/ 1.0 3) r-base-fuste)
l-abaco (
*
(/ 13.0 6) r-base-fuste))
(fuste p a-fuste r-base-fuste r-base-coxim)
(coxim (+z p a-fuste) a-coxim r-base-coxim (/ l-abaco 2.0))
(abaco (+z p (+ a-fuste a-coxim)) a-abaco l-abaco))
O seguinte exemplo de utilizao da funo produz a sequncia de colunas
apresentadas na Figura 27:
46
(coluna-dorica (xy 0 0) 10)
(coluna-dorica (xy 10 0) 15)
(coluna-dorica (xy 20 0) 20)
(coluna-dorica (xy 30 0) 25)
(coluna-dorica (xy 40 0) 30)
(coluna-dorica (xy 50 0) 35)
Exerccio 7.10.1 Afuno raio-topo-fuste calcula o valor da varivel local divisoes
mesmo quando o parmetro altura menor ou igual a 15. Redena a funo de
modo a que a varivel divisoes s seja denida valor quando o seu valor real-
mente necessrio.
46
Note-se que, agora, a altura da coluna tem de ser especicada em ps dricos.
104
Figura 27: Variaes de colunas dricas segundo as propores de Vitrvio.
Exerccio 7.10.2 A exponenciao b
n
uma operao entre dois nmeros b e n desig-
nados base e expoente, respectivamente. Quando n um inteiro positivo, a exponen-
ciao dene-se como uma multiplicao repetida:
b
n
= b b b

n
Embora a denio anterior seja sucientemente clara para um ser humano, no
utilizvel por um computador. Porqu? Justique a sua resposta.
Exerccio 7.10.3 Sugira uma denio matemtica da exponenciao que permita a
sua fcil traduo para uma linguagem de programao.
7.11 Operaes com Coordenadas
Vimos, na seco 4.1, a denio e implementao de um tipo abstracto para
coordenadas bi-dimensionais que assentava nas seguinte funes:
(defun xy (x y)
(list x y))
(defun cx (c)
(car c))
(defun cy (c)
(cadr c))
105
Vimos tambm, na seco 4.6 que possvel denir as coordenadas tri-
dimensionais como uma generalizao bvia do tipo anterior. Para isso, bastou-
nos preservar as posies das coordenadas bi-dimensionais x e y na represen-
tao de coordenadas tri-dimensionais, o que implica colocarmos a coorde-
nada z a seguir s outras duas. Isto levou-nos a denir o construtor de coor-
denadas Cartesianas tri-dimensionais xyz com a seguinte forma:
(defun xyz (x y z)
(list x y z))
O correspondente selector da coordenada z cou ento denido como:
(defun cz (c)
(caddr c))
Uma vez que adoptmos uma representao de coordenadas tri-dimensionais
que uma extenso da representao correspondente para coordenadas bi-
dimensionais, os selectores cx e cy que eram vlidos para coordenadas bi-
dimensionais passarama ser vlidos tambmpara coordenadas tri-dimensionais.
Infelizmente, o inverso j no necessariamente verdade: o selector cz no
pode ser aplicado a coordenadas bi-dimensionais pois estas no possuem,
na sua representao, esta terceira coordenada. No entanto, possvel ge-
neralizar este selector de modo a torn-lo aplicvel tambm a coordenadas
bi-dimensionais, simplesmente assumindo que o caso bi-dimensional se de-
senrola no plano z = 0, i.e., assumindo que (x, y) = (x, y, 0). Em termos
de implementao, para que o selector cz seja compatvel com coordenadas
bi- ou tri-dimensionais, ele precisa de saber distinguir as duas representaes.
Uma vez que uma das representaes uma lista de dois elementos e a outra
uma lista de trs elementos, o mais simples testar se existe algo para l do
segundo elemento. Assim, vamos previamente denir um reconhecedor para
cada tipo de coordenada:
(defun xy? (c)
(null (cddr c)))
(defun xyz? (c)
(not (null (cddr c))))
Usando estas funes agora mais simples denir correctamente o selector
cz: para coordenadas bi-dimensionais, devolve zero. Para coordenadas tri-
dimensionais, devolve o terceiro elemento da lista de coordenadas.
(defun cz (c)
(if (xy? c)
0
(caddr c)))
de salientar que o selector cz precisa de testar o seu argumento para
decidir o que devolver. Este teste e escolha do caminho a seguir a marca da
estrutura de controle de seleco.
106
A redenio do selector cz para lidar com os dois tipos de coordenadas
tem a vantagem adicional de permitir que outras funes de coordenadas tri-
dimensionais se possam aplicar a coordenadas bi-dimensionais. Por exemplo,
a seguinte funo de coordenadas tri-dimensionais, denida na seco 4.5,
(defun +xyz (c x y z)
(xyz (+ (cx c) x)
(+ (cy c) y)
(+ (cz c) z)))
passa a ser directamente aplicvel a coordenadas bi-dimensionais sem qual-
quer tipo de alterao.
Infelizmente, nem todas as funes conseguem funcionar inalteradas. Por
exemplo, consideremos a funo +xy que permitia deslocar coordenadas bi-
dimensionais:
(defun +xy (c x y)
(xy (+ (cx c) x)
(+ (cy c) y)))
Como bvio pela anlise da funo anterior, se ela for aplicada a uma
coordenada tri-dimensional, perde-se a coordenada z, o que manifestamente
indesejvel. Para evitar este problema e, ao mesmo tempo, preservar a com-
patibilidade com o caso bi-dimensional, temos de distinguir os dois casos:
(defun +xy (c x y)
(if (xy? c)
(xy (+ (cx c) x)
(+ (cy c) y))
(xyz (+ (cx c) x)
(+ (cy c) y)
(cz c))))
Como exemplo, temos:
_$ (+xy (xy 1 2) 4 5)
(5 7)
_$ (+xy (xyz 1 2 3) 4 5)
(5 7 3)
Para alm da funo +xy tambm usmos anteriormente a funo +pol
que somava a um ponto uma distncia especicada em termos de coorde-
nadas polares:
(defun +pol (c ro fi)
(+xy c
(
*
ro (cos fi))
(
*
ro (sin fi))))
107
Uma vez que a funo +pol est denida em termos da funo +xy e esta
j sabe tratar coordenadas tri-dimensionais, tambm +pol saber tratar coor-
denadas tri-dimensionais e, consequentemente, no precisa de ser redenida.
O mesmo se pode dizer das funes +x e +y que apenas dependem de +xy.
Finalmente, consideremos a denio da funo +c que apresentmos na
seco 4.11 e que se destinava a deslocar um ponto ao longo de um vector
(especicado pelas coordenadas da sua extremidade):
(defun +c (p0 p1)
(xy (+ (cx p0) (cx p1))
(+ (cy p0) (cy p1))))
evidente pela denio da funo que ela no aplicvel ao caso tri-
dimensional pois s lida com as coordenadas x e y de ambos os pontos. Para
lidar correctamente com o caso tri-dimensional teremos de ter em conta que
qualquer um dos parmetros pode corresponder a um ponto em coordenadas
tri-dimensionais e que ser apenas quando ambos os parmetros forem coorde-
nadas bi-dimensionais que poderemos usar a denio anterior. Assim, temos:
(defun +c (p0 p1)
(if (and (xy? p0) (xy? p1))
(xy (+ (cx p0) (cx p1))
(+ (cy p0) (cy p1)))
(xyz (+ (cx p0) (cx p1))
(+ (cy p0) (cy p1))
(+ (cz p0) (cz p1)))))
Agora, temos:
_$ (+c (xy 1 2) (xy 3 4))
(4 6)
_$ (+c (xy 1 2) (xyz 3 4 5))
(4 6 5)
_$ (+c (xyz 0 1 2) (xy 3 4))
(3 5 2)
_$ (+c (xyz 0 1 2) (xyz 3 4 5))
(3 5 7)
Para alm da soma de um vector a um ponto por vezes til considerar
a operao inversa, que subtrai um vector a um ponto, i.e., que determina a
origem do vector cujo destino o ponto dado ou, equivalentemente, as projec-
es do vector que liga os dois pontos dados. Por analogia com a operao +c,
vamos denominar esta operao de -c e a sua denio ser, obviamente:
(defun -c (p0 p1)
(if (and (xy? p0) (xy? p1))
(xy (- (cx p0) (cx p1))
(- (cy p0) (cy p1)))
(xyz (- (cx p0) (cx p1))
(- (cy p0) (cy p1))
(- (cz p0) (cz p1)))))
108
Agora, temos:
_$ (-c (xy 4 6) (xy 3 4))
(1 2)
_$ (-c (xy 4 6) (xy 1 2))
(3 4))
_$ (-c (xyz 4 6 3) (xyz 1 2 3))
(3 4 0)
_$ (-c (xyz 4 6 5) (xy 1 2))
(3 4 5)
_$ (-c (xyz 5 7 9) (xyz 1 2 3))
(4 5 6)
Pode ser tambm til poder multiplicar uma coordenada por um factor,
correspondendo a uma simples homotetia. Mais uma vez, temos de distinguir
os dois casos de pontos bi- e tri-dimensionais:
(defun
*
c (p f)
(if (xy? p)
(xy (
*
(cx p) f)
(
*
(cy p) f))
(xyz (
*
(cx p) f)
(
*
(cy p) f)
(
*
(cz p) f))))
Como se pode ver pelas denies anteriores, a estrutura de controle de
seleco fundamental para se poder obter os diferentes comportamentos ne-
cessrios para tratar o caso de coordenadas Cartesianas bi-dimensionais ou
tri-dimensionais.
Finalmente, para alm das operaes de adio e subtraco de coordena-
das, pode ser til uma operao de comparao de coordenadas que designa-
remos por =c. Duas coordenadas sero iguais se as suas componentes x, y e z
forem iguais, i.e.:
(defun =c (c0 c1)
(and (= (cx c0) (cx c1))
(= (cy c0) (cy c1))
(= (cz c0) (cz c1))))
A funo anterior funciona igualmente bem com coordenadas bidimensio-
nal, tridimensionais ou mistas pois elas s podero diferir na presena, ou no,
da coordenada z mas o selector cz encarrega-se de esconder essa diferena.
O conjunto de funes que descrevemos atrs e que inclui os construtores
xy, +xy, xyz, +xyz, +x, +y, +z, +c, -c e
*
c, os selectores cx, cy e cz, os reco-
nhecedores xy? e xyz? e, nalmente, o teste =c constituem um tipo abstracto
para coordenadas Cartesianas que iremos frequentemente usar de futuro.
Para alm das coordenadas Cartesianas, ainda usual empregarem-se dois
outros sistemas de coordenadas que iremos ver de seguida: as coordenadas ci-
lndricas e as coordenadas esfricas.
109
y
z
x
P
z

Figura 28: Coordenadas cilndricas.


7.12 Coordenadas Cilndricas
Tal como podemos vericar na Figura 28, um ponto, em coordenadas cilndri-
cas, caracteriza-se por um raio assente no plano z = 0, um ngulo que esse
raio faz com o eixo x e por uma cota z. fcil de ver que o raio e o ngulo
correspondem s coordenadas polares da projeco do ponto no plano z = 0.
Dado um ponto (, , z) em coordenadas cilndricas, o mesmo ponto em
coordenadas Cartesianas
( cos , sin, z)
De igual modo, dado um ponto (x, y, z) em coordenadas Cartesianas, o
mesmo ponto em coordenadas cilndricas
(

x
2
+ y
2
, atan
y
x
, z)
Estas equivalncias permitem-nos denir uma funo que constri pontos
em coordenadas cilndricas empregando as coordenadas Cartesianas como re-
presentao cannica:
(defun cil (ro fi z)
(xyz (
*
ro (cos fi))
(
*
ro (sin fi))
z))
No caso de pretendermos simplesmente somar a um ponto um vector em
coordenadas cilndricas, podemos tirar partido da funo +c e denir:
(defun +cil (p ro fi z)
(+c p (cil ro fi z)))
Exerccio 7.12.1 Dena os selectores cil-ro, cil-fi e cil-z que devolvem, res-
pectivamente, os componentes , e z de um ponto construdo pelo construtor cil.
110
y
z
x
P

Figura 29: Coordenadas Esfricas


Existem inmeras curvas, superfcies e volumes que so mais simples-
mente descritos usando coordenadas cilndricas do que usando coordenadas
rectangulares. Por exemplo, a equao paramtrica de uma hlice, em coorde-
nadas cilndricas, trivial:
(, , z) = (1, t, t)
No entanto, em coordenadas rectangulares, somos obrigados a empregar al-
guma trigonometria para obter a equao equivalente:
(x, y, z) = (cos t, sint, t)
7.13 Coordenadas Esfricas
Tal como podemos ver na Figura 29, umponto, emcoordenadas esfricas (tam-
bm denominadas polares), caracteriza-se pelo comprimento do raio vector,
por um ngulo (denominado longitude ou azimute) que a projeco desse vec-
tor no plano z = 0 faz com o eixo x e por ngulo (denominado colatitude
47
,
znite ou ngulo polar) que o vector faz com o eixo z.
Dado um ponto (, , ) em coordenadas esfricas, o mesmo ponto em co-
ordenadas Cartesianas
( sin cos , sin sin, cos )
De igual modo, dado um ponto (x, y, z) em coordenadas Cartesianas, o
mesmo ponto em coordenadas esfricas
(

x
2
+ y
2
+ z
2
, atan
y
x
, atan

x
2
+ y
2
z
)
47
A colatitude , como bvio, o ngulo complementar latitude, i.e., a diferena entre o
plo (

2
) e a latitude.
111
Tal como zemos para as coordenadas cilndricas, vamos denir o constru-
tor de coordenadas esfricas e a soma de um ponto a um vector em coordena-
das esfricas:
(defun esf (ro fi psi)
(xyz (
*
ro (sin psi) (cos fi))
(
*
ro (sin psi) (sin fi))
(
*
ro (cos psi))))
(defun +esf (p ro fi psi)
(+c p (esf ro fi psi)))
Exerccio 7.13.1 Dena os selectores esf-ro, esf-fi e esf-psi que devolvem, res-
pectivamente, os componentes , e de um ponto construdo pelo construtor esf.
112
7.14 Recurso
Vimos que as nossas funes, para fazerem algo til, precisam de invocar ou-
tras funes. Por exemplo, se j tivermos a funo que calcula o quadrado
de um nmero e pretendermos denir a funo que calcula o cubo de um n-
mero, podemos facilmente faz-lo custa do quadrado e de uma multiplicao
adicional, i.e.:
(defun cubo (x)
(
*
(quadrado x) x))
Do mesmo modo, podemos denir a funo quarta-potencia custa
do cubo e de uma multiplicao adicional, i.e.:
(defun quarta-potencia (x)
(
*
(cubo x) x))
Como bvio, podemos continuar a denir sucessivamente novas funes
para calcular potncias crescentes mas isso no s moroso como ser sempre
limitado. Seria muito mais til podermos generalizar o processo e denir sim-
plesmente a funo potncia que, a partir de dois nmeros (a base e o expoente)
calcula o primeiro elevado ao segundo.
No entanto, aquilo que zemos para a quarta-potencia, o cubo e o
quadrado do-nos uma pista muito importante: se tivermos uma funo que
calcula a potncia de expoente imediatamente inferior, ento basta-nos uma multipli-
cao adicional para calcular a potncia seguinte.
Dito de outra forma, temos:
(defun potencia (x n)
(
*
(potencia-inferior x n) x))
Embora tenhamos conseguido simplicar o problema do clculo de po-
tncia, sobrou uma questo por responder: como podemos calcular a potn-
cia imediatamente inferior? A resposta poder no ser bvia mas, uma vez
percebida, trivial: a potncia imediatamente inferior potncia de expoente n
a potncia de expoente (n 1). Isto implica que (potencia-inferior x n)
exactamente o mesmo que (potencia x (- n 1)). Com base nesta ideia,
podemos reescrever a denio anterior:
(defun potencia (x n)
(
*
(potencia x (- n 1)) x))
Apesar da nossa soluo engenhosa, esta denio temumproblema: qual-
quer que seja a potncia que tentemos calcular, nunca conseguiremos obter o
resultado nal. Para percebermos este problema, mais simples usar um caso
real: tentemos calcular a terceira potncia do nmero 4, i.e., (potencia 4 3).
Para isso, de acordo com a denio da funo potencia, ser preciso
avaliar a expresso
(
*
(potencia 4 2) 4)
113
que, por sua vez, implica avaliar
(
*
(
*
(potencia 4 1) 4) 4)
que, por sua vez, implica avaliar
(
*
(
*
(
*
(potencia 4 0) 4) 4) 4)
que, por sua vez, implica avaliar
(
*
(
*
(
*
(
*
(potencia 4 -1) 4) 4) 4) 4)
que, por sua vez, implica avaliar
(
*
(
*
(
*
(
*
(
*
(potencia 4 -2) 4) 4) 4) 4) 4)
que, por sua vez, implica avaliar
(
*
(
*
(
*
(
*
(
*
(
*
(potencia 4 -3) 4) 4) 4) 4) 4) 4)
que, por sua vez, implica avaliar . . .
fcil vermos que este processo nunca mais termina. O problema est no
facto de termos reduzido o clculo da potncia de um nmero elevado a um
expoente ao clculo da potncia desse nmero elevado ao expoente imediata-
mente inferior mas no dissmos em que situao que j temos um expoente
sucientemente simples cuja soluo seja imediata. Quais so as situaes em
que isso acontece? J vimos que quando o expoente 2, a funo quadrado
devolve o resultado correcto, pelo que o caso n = 2 j sucientemente sim-
ples. No entanto, possvel ter um caso ainda mais simples: quando o expo-
ente 1, o resultado simplesmente a base. Finalmente, o caso mais simples
de todos: quando o expoente zero, o resultado 1, independentemente da
base. Este ltimo caso fcil de perceber quando vemos que a avaliao de
(potencia 4 2) (i.e., do quadrado de quatro) se reduz, em ltima anlise,
a (
*
(
*
(potencia 4 0) 4) 4). Para que esta expresso seja equivalente a
(
*
4 4) necessrio que (potencia 4 0) seja 1.
Estamos ento em condies de denir correctamente a funo potencia:
1. Quando o expoente zero, o resultado um.
2. Caso contrrio, calculamos a potncia de expoente imediatamente infe-
rior e multiplicamo-la pela base.
(defun potencia (x n)
(if (zerop n)
1
(
*
(potencia x (- n 1)) x)))
A funo anterior um exemplo de uma funo recursiva, i.e., uma funo
que est denida em termos de si prpria. Dito de outra forma, uma funo
recursiva uma funo que se usa a si prpria na sua denio. Esse uso
bvio quando desenrolamos a avaliao de (potencia 4 3):
(potencia 4 3)

(
*
(potencia 4 2) 4)

(
*
(
*
(potencia 4 1) 4) 4)

114
(
*
(
*
(
*
(potencia 4 0) 4) 4) 4)

(
*
(
*
(
*
1 4) 4) 4)

(
*
(
*
4 4) 4)

(
*
16 4)

64
A recurso a estrutura de controle que permite que uma funo se possa
invocar a si prpria durante a sua prpria avaliao. A recurso uma das
mais importantes ferramentas de programao pelo que fundamental que a
percebamos bem. Muitos problemas aparentemente complexos possuem so-
lues recursivas extraordinariamente simples.
Existem inmeros exemplos de funes recursivas. Uma das mais simples
a funo factorial que se dene matematicamente como:
n! =

1, se n = 0
n (n 1)!, caso contrrio.
A traduo desta frmula para Lisp directa:
(defun factorial (n)
(if (zerop n)
1
(
*
n (factorial (- n 1)))))
importante repararmos que em todas as funes recursivas existe:
Um caso bsico (tambm chamado caso de paragem) cujo resultado ime-
diatamente conhecido.
Um caso no bsico (tambm chamado caso recursivo) em que se trans-
forma o problema original num sub-problema mais simples.
Se analisarmos a funo factorial, o caso bsico o teste de igualdade a
zero (zerop n), o resultado imediato 1, e o caso recursivo , obviamente,
(
*
n (factorial (- n 1))).
Geralmente, uma funo recursiva s est correcta se tiver uma expresso
condicional que identique o caso bsico, mas no obrigatrio que assimseja.
A invocao de uma funo recursiva consiste em ir resolvendo subproblemas
sucessivamente mais simples at se atingir o caso mais simples de todos, cujo
resultado imediato. Desta forma, o padro mais comum para escrever uma
funo recursiva :
Comear por testar os casos bsicos.
Fazer uma invocao recursiva com um subproblema cada vez mais pr-
ximo de um caso bsico.
115
Usar o resultado da invocao recursiva para produzir o resultado da
invocao original.
Dado este padro, os erros mais comuns associados s funes recursivas
so, naturalmente:
No detectar um caso bsico.
A recurso no diminuir a complexidade do problema, i.e., no passar
para um problema mais simples.
No usar correctamente o resultado da recurso para produzir o resul-
tado originalmente pretendido.
Repare-se que uma funo recursiva que funciona perfeitamente para os
casos para que foi prevista pode estar completamente errada para outros ca-
sos. A funo factorial um exemplo: quando o argumento negativo,
o problema torna-se cada vez mais complexo, cada vez mais longe do caso
simples:
(factorial -1)

(
*
-1 (factorial -2))

(
*
-1 (
*
-2 (factorial -3)))

(
*
-1 (
*
-2 (
*
-3 (factorial -4))))

(
*
-1 (
*
-2 (
*
-3 (
*
-4 (factorial -5))))))

(
*
-1 (
*
-2 (
*
-3 (
*
-4 (
*
-5 (factorial -6))))))

...
O caso mais frequente de erro numa funo recursiva a recurso nunca
parar, ou porque no se detecta correctamente o caso bsico ou por a recurso
no diminuir a complexidade do problema. Neste caso, o nmero de invoca-
es recursivas cresce indenidamente at esgotar a memria do computador,
altura em que o programa gera um erro. No caso do Auto Lisp, esse erro no
inteiramente bvio pois o avaliador apenas interrompe a avaliao sem apre-
sentar qualquer resultado. Eis um exemplo:
_$ (factorial 3)
6
_$ (factorial -1)
_$
116
muito importante compreendermos bem o conceito de recurso. Em-
bora a princpio possa ser difcil abarcar por completo as implicaes deste
conceito, a recurso permite resolver, com enorme simplicidade, problemas
aparentemente muito complexos.
Como iremos ver, tambm em arquitectura a recurso um conceito fun-
damental.
Exerccio 7.14.1 A funo de Ackermann denida para nmeros no negativos da
seguinte forma:
A(m, n) =

n + 1 se m = 0
A(m1, 1) se m > 0 e n = 0
A(m1, A(m, n 1)) se m > 0 e n > 0
Dena, em Lisp, a funo de Ackermann.
Exerccio 7.14.2 Indique o valor de
1. (ackermann 0 8)
2. (ackermann 1 8)
3. (ackermann 2 8)
4. (ackermann 3 8)
5. (ackermann 4 8)
Exerccio 7.14.3 Dena uma funo denominada escada que, dado um ponto P, um
nmero de degraus, o comprimento do espelho e e o comprimento do cobertor c de
cada degrau, desenha a escada emAutoCad como primeiro espelho a comear a partir
do ponto dado, tal como se v na imagem seguinte:
c
e
P
Exerccio 7.14.4 Considere o desenho de crculos em torno de um centro, tal como
apresentado na seguinte imagem:
x
y
p
r
0
r
1

117
Escreva uma funo denominada circulos-concentricos que, a partir das
coordenadas p do centro de rotao, do nmero de crculos n, do raio de translaco
r
0
, do raio de circunferncia r
1
, do ngulo inicial e do incremento de ngulo ,
desenha os crculos tal como apresentados na gura anterior.
Teste a sua funo com os seguintes expresses:
(circulos-concentricos (xy 0 0) 10 10 2 0 (/ pi 5))
(circulos-concentricos (xy 25 0) 20 10 2 0 (/ pi 10))
(circulos-concentricos (xy 50 0) 40 10 2 0 (/ pi 20))
cuja avaliao dever gerar a imagem seguinte:
Exerccio 7.14.5 Considere o desenho de ores simblicas compostas por um crculo
interior em torno da qual esto dispostos crculos concntricos correspondentes a p-
talas. Estes crculos devero ser tangentes uns aos outros e ao crculo interior, tal como
se apresenta na seguinte imagem:
Dena a funo flor que recebe apenas o ponto correspondente ao centro da or,
o raio do crculo interior e o nmero de ptalas.
Teste a sua funo com as expresses
118
(flor (xy 0 0) 5 10)
(flor (xy 18 0) 2 10)
(flor (xy 40 0) 10 20)
que devero gerar a imagem seguinte:
7.15 Depurao de Programas Recursivos
Vimos, na seco 4.19 que os erros de um programa se podem classicar em
termos de erros sintticos ou erros semnticos. Os erros sintticos ocorrem
quando escrevemos frases invlidas na linguagem. Como exemplo de erro
sinttico, consideremos a seguinte denio da funo potencia onde nos
esquecemos da lista de parmetros:
(defun potencia
(if (= n 0)
1
(
*
(potencia x (- n 1)) x)))
Este esquecimento o suciente para baralhar o Auto Lisp: ele esperava
encontrar a lista de parmetros imediatamente a seguir a nome da funo e
que, no lugar dela, encontra uma lista que comea com o smbolo if. Isto
faz com que o Auto Lisp erradamente acredite que o smbolo if o nome do
primeiro parmetro e, da para a frente, a sua confuso s aumenta. A dado
momento, quando o Auto Lisp deixa, por completo, de compreender aquilo
que se pretendia denir, apresenta-nos um erro.
Os erros semnticos so mais complexos que os sintticos pois, em geral,
s podem ser detectados durante a execuo do programa.
48
Por exemplo, se
tentarmos calcular o factorial de uma string iremos ter um erro, tal como o
seguinte exemplo mostra:
48
H casos de erros semnticos que podem ser detectados antes da execuo do programa
mas essa deteco depende muito da qualidade da implementao da linguagem e da sua ca-
pacidade em antecipar as consequncias dos programas.
119
_$ (factorial 5)
120
_$ (factorial "cinco")
; error: bad argument type: numberp: "cinco"
Este ltimo erro, como bvio, no tem a ver com a regras da gramtica do
Lisp: a frase da invocao da funo factorial est correcta. O problema
est no facto de no fazer sentido calcular o factorial de uma string pois o
clculo do factorial envolve operaes aritmticas e estas no so aplicveis a
strings. Assim sendo, o erro tem a ver com o signicado da frase escrita, i.e.,
com a semntica. Trata-se, portanto, de um erro semntico.
A recurso innita outro exemplo de um erro semntico. Vimos que a
funo factorial s pode ser invocada com um argumento no negativo ou
provoca recurso innita. Consequentemente, se usarmos um argumento ne-
gativo estaremos a cometer um erro semntico.
7.15.1 Trace
Vimos, na seco4.19, que o Visual Lisp disponibiliza vrios mecanismos para
fazermos a deteco de erros. Um dos mais simples a forma trace que per-
mite visualizar as invocaes das funes. A forma trace recebe o nome das
funes cuja invocao se pretende analizar e altera essas funes de forma a
que elas escrevam as sucessivas invocaes com os respectivos argumentos,
bem como o resultado da invocao. Se o ambiente do Visual Lisp estiver
activo, a escrita feita numa janela especial do ambiente do Visual Lisp deno-
minada Trace, caso contrrio, feita na janela de comandos do AutoCad. A
informao apresentada em resultado do trace , em geral, extremamente til
para a depurao das funes.
Por exemplo, para visualizarmos uma invocao da funo factorial,
consideremos a seguinte interaco:
_$ (trace factorial)
FACTORIAL
_$ (factorial 5)
120
Em seguida, se consultarmos o contedo da janela de Trace, encontramos:
Entering (FACTORIAL 5)
Entering (FACTORIAL 4)
Entering (FACTORIAL 3)
Entering (FACTORIAL 2)
Entering (FACTORIAL 1)
Entering (FACTORIAL 0)
Result: 1
Result: 1
Result: 2
Result: 6
Result: 24
Result: 120
120
Note-se, no texto anterior escrito em consequncia do trace, que a invo-
cao que zemos da funo factorial aparece encostada esquerda. Cada
invocao recursiva aparece ligeiramente para a direita, permitindo assim vi-
sualizar a profundidade da recurso, i.e., o nmero de invocaes recursi-
vas. O resultado devolvido por cada invocao aparece alinhado na mesma
coluna dessa invocao.
de salientar que a janela de Trace no tem dimenso innita, pelo que as
recurses excessivamente profundas acabaro por no caber na janela. Neste
caso, o Visual Lisp reposiciona a escrita na coluna esquerda mas indica nume-
ricamente o nvel de profundidade em que se encontra. Por exemplo, para o
(factorial 15), aparece:
Entering (FACTORIAL 15)
Entering (FACTORIAL 14)
Entering (FACTORIAL 13)
Entering (FACTORIAL 12)
Entering (FACTORIAL 11)
Entering (FACTORIAL 10)
Entering (FACTORIAL 9)
Entering (FACTORIAL 8)
Entering (FACTORIAL 7)
Entering (FACTORIAL 6)
[10] Entering (FACTORIAL 5)
[11] Entering (FACTORIAL 4)
[12] Entering (FACTORIAL 3)
[13] Entering (FACTORIAL 2)
[14] Entering (FACTORIAL 1)
[15] Entering (FACTORIAL 0)
[15] Result: 1
[14] Result: 1
[13] Result: 2
[12] Result: 6
[11] Result: 24
[10] Result: 120
Result: 720
Result: 5040
Result: 40320
Result: 362880
Result: 3628800
Result: 39916800
Result: 479001600
Result: 1932053504
Result: 1278945280
Result: 2004310016
No caso de recurses innitas, apenas so mostradas as ltimas invocaes
realizadas antes de ser gerado o erro. Por exemplo, para (factorial -1),
teremos:
...
[19215] Entering (FACTORIAL -19216)
121
[19216] Entering (FACTORIAL -19217)
[19217] Entering (FACTORIAL -19218)
[19218] Entering (FACTORIAL -19219)
[19219] Entering (FACTORIAL -19220)
[19220] Entering (FACTORIAL -19221)
[19221] Entering (FACTORIAL -19222)
[19222] Entering (FACTORIAL -19223)
[19223] Entering (FACTORIAL -19224)
[19224] Entering (FACTORIAL -19225)
...
[19963] Entering (FACTORIAL -19964)
[19964] Entering (FACTORIAL -19965)
[19965] Entering (FACTORIAL -19966)
[19966] Entering (FACTORIAL -19967)
[19967] Entering (FACTORIAL -19968)
[19968] Entering (FACTORIAL -19969)
[19969] Entering (FACTORIAL -19970)
[19970] Entering (FACTORIAL -19971)
[19971] Entering (FACTORIAL -19972)
[19972] Entering (FACTORIAL -19973)
[19973] Entering (FACTORIAL -19974)
[19974] Entering (FACTORIAL -19975)
[19975] Entering (FACTORIAL -19976)
Para se parar a depurao de uma funo, usa-se a forma especial untrace,
que recebe o nome da funo ou funes que se pretende retirar do trace.
Exerccio 7.15.1 Faa o trace da funo potncia. Qual o trace resultante da avaliao
(potencia 2 10)?
Mais frente iremos ver outras ferramentas de depurao do Visual Lisp.
Exerccio 7.15.2 Dena uma funo circulos capaz de criar a gura apresentada
em seguida:
Note que os crculos possuem raios que esto em progresso geomtrica de razo
1
2
. Dito de outra forma, os crculos mais pequenos tmmetade do raio do crculo maior
que lhes adjacente. Os crculos mais pequenos de todos tm raio maior ou igual a 1.
A sua funo dever ter como parmetros apenas o centro e o raio do crculo maior.
122
Exerccio 7.15.3 Dena uma funo denominada serra que, dado um ponto P, um
nmero de dentes, o comprimento c de cada dente e a altura a de cada dente, desenha
uma serra em AutoCad com o primeiro dente a comear a partir do ponto P, tal como
se v na imagem seguinte:
c
a
P
Exerccio 7.15.4 Dena uma funo losangulos capaz de criar a gura apresentada
em seguida:
Note que os losngulos possuem dimenses que esto em progresso geomtrica
de razo
1
2
. Dito de outra forma, os losngulos mais pequenos tm metade do tama-
nho do losngulo maior em cujas extremidades esto centrados. Os losngulos mais
pequenos de todos tm largura maior ou igual a 1. A sua funo dever ter como
parmetros apenas o centro e a largura do losngulo maior.
7.16 Templos Dricos
Vimos, pelas descries de Vitrvio, que os Gregos criaram um elaborado sis-
tema de propores para colunas. Estas colunas eram usadas para a criao
de prticos, em que uma sucesso de colunas encimadas por um telhado ser-
via de entrada para os edifcios e, em particular, para os templos. Quando
esse arranjo de colunas era avanado em relao ao edifcio, denominava-se o
mesmo de prstilo, classicando-se este pelo nmero de colunas que possuem
em Distilo, Tristilo, Tetrastilo, Pentastilo, Hexastilo, etc. Quando o prstilo se
alargava a todo o edifcio, colocando colunas a toda a sua volta, denominava-
se de peristilo.
Para alm de descrever as propores das colunas, Vitrvio tambm expli-
cou no seu famoso tratado as regras que se deviam seguir para a separao
entre colunas, distinguindo vrios casos de templos, desde aqueles em que
o espao entre colunas era muito reduzido (picnostilo) at aos templos com
espaamento excessivamente alargado (araeostilo), passando pelo seu favorito
(eustilo) em que o espao entre colunas varivel, sendo maior nas colunas
centrais.
Na prtica, nem sempre as regras propostas por Vitrvio representavam a
realidade dos templos e, frequentemente, a distancia intercolunar varia, sendo
mais reduzida nas extremidades para dar um aspecto mais robusto ao templo.
123
Para simplicar a nossa implementao, vamos ignorar estes detalhes e, ao
invs de distinguir vrios stilo, vamos simplesmente usar como parmetros as
coordenadas da base do eixo da primeira coluna, a altura da coluna, a sepa-
rao entre os eixos das colunas
49
(em termos de um vector de deslocao
entre colunas) e, nalmente, o nmero de colunas que pretendemos colocar. O
vector de deslocao entre colunas destina-se a permitir orientar as colunas
em qualquer direco e no s ao longo do eixo dos x ou y.
O raciocnio para a denio desta funo , mais uma vez, recursivo:
Se o nmero de colunas a colocar for zero, ento no preciso fazer nada.
Caso contrrio, colocamos uma coluna na coordenada indicada e, recur-
sivamente, colocamos as restantes colunas a partir da coordenada que
resulta de aplicarmos o vector de deslocao coordenada actual.
Traduzindo este raciocnio para Lisp, temos:
(defun colunas-doricas (p altura separacao colunas)
(if (= colunas 0)
nil
(progn
(coluna-dorica p altura)
(colunas-doricas (+c p separacao)
altura
separacao
(- colunas 1)))))
Note-se que, quando o nmero de colunas maior que zero, h duas ope-
raes a realizar:
Colocar uma coluna.
Colocar o resto das colunas.
Como so duas aces que queremos realizar sequencialmente, usmos o
operador progn para as agrupar numa aco conjunta.
Finalmente, podemos testar a criao das colunas usando, por exemplo:
(colunas-doricas (xy 0 0) 10 (xy 5 0) 8)
cujo resultado est apresentado na Figura 30:
A partir do momento em que sabemos construir uma leira de colunas
torna-se relativamente fcil a construo das quatro leiras necessrias para
os templos em peristilo. Normalmente, a descrio destes templos faz-se em
termos do nmero de colunas da fronte e do nmero de colunas do lado, mas
assumindo que as colunas dos cantos contam para ambas as medidas. Isto
quer dizer que num templo de, por exemplo, 6 12 colunas existem, na reali-
dade, apenas 4 2 + 10 2 + 4 = 32 colunas. Para a construo do peristilo,
49
A denominada distncia interaxial, por oposio distncia intercolunar que mede o es-
pao aberto entre colunas adjacentes.
124
Figura 30: Uma perspectiva de um conjunto de oito colunas dricas com 10
unidades de altura e 5 unidades de separao entre os eixos da colunas ao
longo do eixo x.
para alm do nmero de colunas das frontes e lados, ser necessrio conhecer
a distncia entre colunas nas frontes e nos lados e, claro, a altura das colunas.
Em termos de algoritmo, vamos comear por construir as frontes, dese-
nhando todas as colunas incluindo os cantos. Em seguida construmos os la-
dos, tendo em conta que os cantos j foram colocados. Para simplicar, vamos
considerar que o templo tem as frontes paralelas ao eixo x (e os lados para-
lelos ao eixo y) e que a primeira coluna colocada num ponto P dado como
primeiro parmetro. Assim, temos:
(defun peristilo-dorico (p
n-fronte n-lado
d-fronte d-lado
altura)
(colunas-doricas p
altura (xy d-fronte 0) n-fronte)
(colunas-doricas (+xy p 0 (
*
(1- n-lado) d-lado))
altura (xy d-fronte 0) n-fronte)
(colunas-doricas (+xy p 0 d-lado)
altura (xy 0 d-lado) (- n-lado 2))
(colunas-doricas (+xy p (
*
(1- n-fronte) d-fronte) d-lado)
altura (xy 0 d-lado) (- n-lado 2)))
Para um exemplo realista podemos considerar o templo de Segesta que se
encontra representado da Figura 12. Este templo do tipo peristilo, composto
por 6 colunas (i.e., Hexastilo) em cada fronte e 14 colunas nos lados, num total
125
Figura 31: Uma perspectiva do peristilo do templo de Segesta. As colunas
foram geradas pela funo peristilo-dorico usando, como parmetros,
6 colunas na fronte e 14 no lado, com distncia intercolunar de 4.8 metros na
fronte e 4.6 metros no lado e colunas de 9 metros de altura.
de 36 colunas de 9 metros de altura. A distncia entre os eixos das colunas
de aproximadamente 4.8 metros nas frontes e de 4.6 nos lados. A expresso
que cria o peristilo deste templo , ento:
(peristilo-dorico (xy 0 0) 6 14 4.8 4.6 9)
O resultado da avaliao da expresso anterior est representado na Fi-
gura 31
Embora a grande maioria dos templos Gregos fossemde formato rectangu-
lar, tambm foram construdos templos de formato circular a que chamaram
Tholos. O Santurio de Atenas Pronaia, em Delfos, contm um bom exemplo
de um destes edifcios. Embora pouco reste deste templo, no difcil imagi-
nar a sua forma original a partir do que ainda visvel na Figura 32.
Para simplicar a construo do Tholos, vamos dividi-lo em duas partes.
Numa, iremos desenhar a base e, na outra, iremos posicionar as colunas.
Para o desenho da base, podemos considerar um conjunto de cilindros
achatados, sobrepostos de modo a formar degraus circulares, tal como se apre-
senta na Figura 33. Desta forma, a altura total da base a
b
ser dividida em
passos de a
b
e o raio da base tambm ser reduzido em passos de r
b
.
Para cada cilindro teremos de considerar o seu raio e a altura do espelho
do degrau d-altura. Para passarmos ao cilindro seguinte temos ainda de ter
em conta o aumento do raio d-raio devido ao comprimento do cobertor do
degrau. Estes degraus sero construdos segundo um processo recursivo:
126
Figura 32: OTemplo de Atenas Pronaia emDelfos, construdo no sculo quarto
antes de Cristo. Fotograa de Michelle Kelley
x
z
r
b
r
b
a
b
r
p
Figura 33: Corte da base de um Tholos. A base composta por uma sequncia
de cilindros sobrepostos cujo raio de base r
b
encolhe de r
b
a cada degrau e
cuja altura incrementa a
b
a cada degrau.
127
Se o nmero de degraus a colocar zero, no preciso fazer nada.
Caso contrrio, colocamos um degrau (modelado por um cilindro) com
o raio e a altura do degrau e, recursivamente, colocamos os restantes de-
graus em cima deste, i.e., numa cota igual altura do degrau agora co-
locado e com um raio reduzido do comprimento do cobertor do degrau
agora colocado.
Este processo implementado pela seguinte funo:
(defun base-tholos (p n-degraus raio d-altura d-raio)
(if (= n-degraus 0)
nil
(progn
(command "_.cylinder" p raio d-altura)
(base-tholos (+xyz p 0 0 d-altura)
(- n-degraus 1)
(- raio d-raio)
d-altura
d-raio))))
Para o posicionamento das colunas, vamos tambm considerar um pro-
cesso em que em cada passo apenas posicionamos uma coluna numa dada
posio e, recursivamente, colocamos as restantes colunas a partir da posio
circular seguinte.
Dada a sua estrutura circular, a construo deste gnero de edifcios sim-
plicada pelo uso de coordenadas circulares. De facto, podemos conceber um
processo recursivo que, a partir do raio r
p
do peristilo e do ngulo inicial ,
coloca uma coluna nessa posio e que, de seguida, coloca as restantes colu-
nas usando o mesmo raio mas incrementando o ngulo de , tal como se
apresenta na Figura 34. O incremento angular obtm-se pela diviso da
circunferncia pelo nmero n de colunas a colocar, i.e., =
2
n
. Uma vez
que as colunas se dispem em torno de um crculo, o clculo das coordena-
das de cada coluna ca facilitado pelo uso de coordenadas polares. Tendo este
algoritmo em mente, a denio da funo ca:
(defun colunas-tholos (p n-colunas raio fi d-fi altura)
(if (= n-colunas 0)
nil
(progn
(coluna-dorica (+pol p raio fi) altura)
(colunas-tholos p
(1- n-colunas)
raio
(+ fi d-fi)
d-fi
altura))))
Finalmente, denimos a funo tholos que, dados os parmetros neces-
srios s duas anteriores, as invoca em sequncia:
128
y
z
x
a
b
r
b
r
p
a
p
r
p

Figura 34: Esquema da construo de um Tholos: r


b
o raio da base, r
p
a
distncia do centro das colunas ao centro da base, a
p
a altura das coluna, a
b
a altura da base, o ngulo inicial de posicionamento das colunas e o
ngulo entre colunas.
(defun tholos (p n-degraus rb dab drb n-colunas rp ap)
(base-tholos p n-degraus rb dab drb)
(colunas-tholos (+xyz p 0 0 (
*
n-degraus dab))
n-colunas
rp
0
(/ 2
*
pi n-colunas)
ap))
A Figura 35 mostra a imagem gerada pela avaliao da seguinte expresso:
(tholos (xyz 0 0 0) 3 7.9 0.2 0.2 20 7 4)
Exerccio 7.16.1 Uma observao atenta do Tholos apresentado na Figura 35 mostra
que existe um erro: os bacos das vrias colunas so paralelos uns aos outros (e aos
eixos das abcissas e ordenadas) quando, na realidade, deveriam ter uma orientao
radial. Essa diferena evidente quando se compara uma vista de topo do desenho
actual ( esquerda) coma mesma vista daquele que seria o desenho correcto ( direita):
129
Figura 35: Perspectiva do Tholos de Atenas em Delfos, constitudo por 20 co-
lunas de estilo Drico, de 4 metros de altura e colocadas num crculo com 7
metros de raio.
Dena uma nova funo coluna-dorica-rodada que, para alm da altura da
coluna, recebe ainda o ngulo de rotao que a coluna deve ter. Uma vez que o fuste
e o coxim da coluna tm simetria axial, esse ngulo de rotao s inuencia o baco,
pelo que dever tambm denir uma funo para desenhar um baco rodado.
De seguida, redena a funo colunas-tholos de modo a que cada coluna es-
teja orientada correctamente relativamente ao centro do Tholos.
Exerccio 7.16.2 Considere a construo de uma torre composta por vrios mdulos
em que cada mdulo tem exactamente as mesmas caractersticas de um Tholos, tal
como se apresenta gura abaixo:
130
O topo da torre tem uma forma semelhante da base de um Tholos, embora com
mais degraus.
Dena a funo torre-tholos que, a partir do centro da base da torre, do n-
mero de mdulos, do nmero de degraus a considerar para o topo e dos restantes
parmetros necessrios para denir um mdulo idntico a um Tholos, constri a torre
apresentada anteriormente.
Experimente a sua funo criando uma torre composta por 6 mdulos, com 10
degraus no topo, 3 degraus por mdulo, qualquer deles com comprimento de espelho
e de cobertor de 0.2, raio da base de 7.9 e 20 colunas por mdulo, com raio de peristilo
de 7 e altura de coluna de 4.
Exerccio 7.16.3 Com base na resposta ao exerccio anterior, redena a construo da
torre de forma a que a dimenso radial dos mdulos se v reduzindo medida que se
ganha altura, tal como se apresenta na seguinte imagem:
131
Exerccio 7.16.4 Com base na resposta ao exerccio anterior, redena a construo da
torre de forma a que o nmero de colunas se v tambm reduzindo medida que se
ganha altura, tal como se apresenta na seguinte imagem:
Exerccio 7.16.5 Considere a criao de uma cidade no espao, composta apenas por
cilindros com dimenses progressivamente mais pequenas, unidos uns aos outros por
intermdio de esferas, tal como se apresenta (em perspectiva) na imagem seguinte:
132
Dena uma funo que, a partir do centro da cidade e do raio dos cilindros cen-
trais constri uma cidade semelhante representada.
7.17 A Ordem Jnica
A voluta foi um dos elementos arquitectnicos introduzidos na transio da
Ordem Drica para a Ordem Jnica. Uma voluta um ornamento em forma
de espiral colocado em cada extremo de um capitel Jnico. A Figura 36 mostra
um exemplo de um capitel Jnico contendo duas volutas. Embora tenham so-
brevivido inmeros exemplos de volutas desde a antiguidade, nunca foi claro
o processo do seu desenho.
Vitrvio, no seu tratado de arquitectura, descreve a voluta Jnica: uma
curva em forma de espiral que se inicia na base do baco, desenrola-se numa
srie de voltas e junta-se a um elemento circular denominado o olho.
Vitrvio descreve o processo de desenho da espiral atravs da composi-
o de quartos de circunferncia, comeando pelo ponto mais exterior e dimi-
nuindo o raio a cada quarto de circunferncia, at se dar a conjuno com o
olho. Nesta descrio h ainda alguns detalhes por explicar, em particular, o
posicionamento dos centros dos quartos de circunferncia, mas Vitrvio refere
que ser incluida uma gura e um clculo no nal do livro.
Infelizmente, nunca se encontrou essa gura ou esse clculo, cando assim
por esclarecer um elemento fundamental do processo de desenho de volutas
descrito por Vitrvio. As dvidas sobre esse detalhe tornaram-se ainda mais
evidentes quando a anlise de muitas das volutas que sobreviveram a antigui-
dade revelou diferenas em relao s propores descritas por Vitrvio.
Durante a Renascena, estas dvidas levaram os investigadores a repensar
o mtodo de Vitrvio e a sugerir interpretaes pessoais ou novos mtodos
133
Figura 36: Volutas de um capitel Jnico. Fotograa de See Wah Cheng.
para o desenho da voluta. De particular relevncia foram os mtodos propos-
tos por:
Sebastiano Serlio (1537), baseado na composio de semi-circunferncias,
Giuseppe Salviati (1552), baseado na composio de quartos-de-circun-
ferncia e
Guillaume Philandrier (1544), baseado na composio de oitavos-de-cir-
cunferncia.
Todos estes mtodos diferem em vrios detalhes mas, de forma genrica,
todos se baseiam em empregar arcos de circunferncia de abertura constante
mas raio decrescente. Obviamente, para que haja continuidade nos arcos, os
centros dos arcos vo mudando medida que estes vo sendo desenhados. A
Figura 37 esquematiza o processo para espirais feitas empregando quartos de
circunferncia.
Como se v pela gura, para se desenhar a espiral temos de ir desenhando
sucessivos quartos de circunferncia. O primeiro quarto de circunferncia ser
centrado no ponto (x
0
, y
0
) e ter raio r. Este primeiro arco vai desde o ngulo
/2 at ao ngulo . O segundo quarto de circunferncia ser centrado no
ponto (x
1
, y
1
) e ter raio r f, sendo f um coeciente de reduo da espi-
ral. Este segundo arco vai desde o ngulo at ao ngulo
3
2
. Um detalhe
importante a relao entre as coordenadas p
1
= (x
1
, y
1
) e p
0
= (x
0
, y
0
): para
que o segundo arco tenha uma extremidade coincidente com o primeiro arco,
o seu centro tem de estar na extremidade do vector v
0
de origem em p
0
, com-
primento r(1 f) e ngulo igual ao ngulo nal do primeiro arco.
Este processo dever ser seguido para todos os restantes arcos de circunfe-
rncia, i.e., teremos de calcular as coordenadas (x
2
, y
2
), (x
3
, y
3
), etc., bem como
os raios r f f, r f f f, etc, necessrios para traar os sucessivos arcos de
circunferncia.
134
(x
0
, y
0
)
r
v
0
r f
(x
1
, y
1
)
v
1
r f f
(x
2
, y
2
)
v
2
(x
3
, y
3
)
r f f f
Figura 37: O desenho de uma espiral com arcos de circunferncia.
Dito desta forma, o processo de desenho parece ser complicado. No en-
tanto, possivel reformul-lo de modo a car muito mais simples. De facto,
podemos pensar no desenho da espiral completa como sendo o desenho de um
quarto de circunferncia seguido do desenho de uma espiral mais pequena.
Mais concretamente, podemos especicar o desenho da espiral de centro no
ponto p, raio r e ngulo inicial como sendo o desenho de um arco de circun-
ferncia de raio r centrado em p com ngulo inicial e nal +

2
seguido de
uma espiral de centro em p +v, raio r f e ngulo inicial +

2
. O vector v ter
origem em p, mdulo r(1 f) e ngulo +

2
.
Obviamente, sendo este um processo recursivo, necessrio denir o caso
de paragem, havendo (pelo menos) duas possibilidades:
Terminar quando o raio r inferior a um determinado limite.
Terminar quando o ngulo superior a um determinado limite.
Por agora, vamos considerar a segunda possibilidade. De acordo com o
nosso raciocnio, vamos denir a funo que desenha a espiral de modo a re-
ceber, como parmetros, o ponto inicial p, o raio inicial r, o ngulo inicial
a-ini, o ngulo nal a-fin e o factor de reduo f:
(defun espiral (p r a-ini a-fin f)
(if (> a-ini a-fin)
nil
135
(progn
(quarto-circunferencia p r a-ini)
(espiral (+pol p (
*
r (- 1 f)) (+ a-ini (/ pi 2)))
(
*
r f)
(+ a-ini (/ pi 2))
a-fin
f))))
Reparemos que a funo espiral recursiva pois est denida emtermos
de si prpria. Obviamente, o caso recursivo mais simples que o caso original
pois a diferena entre o ngulo inicial e o nal mais pequena, aproximando-
se progressivamente do caso de paragem em que o ngulo inicial ultrapassa o
nal.
Para desenhar o quarto de circunferncia vamos empregar a operao arc
do Auto Lisp que recebe o centro do circunferncia, o ponto inicial do arco e
o ngulo em graus. Para melhor percebermos o processo de desenho da espi-
ral vamos tambm traar duas linhas com origem no centro a delimitar cada
quarto de circunferncia. Mais tarde, quando tivermos terminado o desenvol-
vimento destas funes, removeremos essas linhas.
Desta forma, o quarto de circunferncia apenas precisa de saber o ponto
p correspondente ao centro da circunferncia, o raio r da mesma e o ngulo
inicial a-ini:
(defun quarto-circunferencia (p r a-ini)
(command "_.arc" "_c" p (+pol p r a-ini) "_a" 90)
(command "_.line" p (+pol p r a-ini) "")
(command "_.line" p (+pol p r (+ a-ini (/ pi 2))) ""))
Podemos agora experimentar um exemplo:
(espiral (xy 0 0) 10 (/ pi 2) (
*
pi 6) 0.8)
A espiral traada pela expresso anterior est representada na Figura 38.
A funo espiral permite-nos denir um sem-nmero de espirais, mas
tem uma restrio: cada arco de crculo corresponde a um ngulo de

2
. Logi-
camente, a funo tornar-se- mais til se tambm este incremento de ngulo
for um parmetro.
As modicaes a fazer so relativamente triviais, bastando acrescentar um
parmetro a-inc representando o incremento de ngulo de cada arco e substi-
tuir as ocorrncias de (/ pi 2) por este parmetro. Naturalmente, em vez de
desenharmos um quarto de circunferncia, temos agora de desenhar um arco
de circunferncia. Temos, contudo, que ter ateno a umdetalhe: o ltimo arco
pode no ser completo se a soma do ngulo inicial com o incremento exceder
o ngulo nal. Neste caso, o arco ter apenas o ngulo remanescente. A nova
denio , ento:
(defun espiral (p r a-ini a-inc a-fin f)
(if (>= (+ a-ini a-inc) a-fin)
(arco p r a-ini a-inc)
136
Figura 38: O desenho da espiral.
(progn
(arco p r a-ini a-inc)
(espiral (+pol p (
*
r (- 1 f)) (+ a-ini a-inc))
(
*
r f)
(+ a-ini a-inc)
a-inc
a-fin
f))))
A funo que desenha o arco uma variante da que desenha o quarto de
circunferncia. Apenas preciso ter em conta que o comando arc pretende o
ngulo em graus e no em radianos, o que nos obriga a usar uma converso:
(defun arco (p r a-ini a-inc)
(command "_.arc"
"_c" p (+pol p r a-ini)
"_a" (graus<-radianos a-inc))
(command "_.line" p (+pol p r a-ini) "")
(command "_.line" p (+pol p r (+ a-ini a-inc)) ""))
(defun graus<-radianos (radianos)
(
*
(/ 180 pi) radianos))
Agora, para desenhar a mesma espiral representada na Figura 38, temos
de avaliar a expresso:
(espiral (xy 0 0) 10 (/ pi 2) (/ pi 2) (
*
pi 6) 0.8)
claro que agora podemos facilmente construir outras espirais. As seguin-
tes expresses produzem as espirais representadas na Figura 39:
(espiral (xy 0 0) 10 (/ pi 2) (/ pi 2) (
*
pi 6) 0.9)
(espiral (xy 20 0) 10 (/ pi 2) (/ pi 2) (
*
pi 6) 0.7)
(espiral (xy 40 0) 10 (/ pi 2) (/ pi 2) (
*
pi 6) 0.5)
137
Figura 39: Vrias espirais com razes de reduo de 0.9, 0.7 e 0.5, respectiva-
mente.
Outra possibilidade de variao est no ngulo de incremento. As seguin-
tes expresses experimentam aproximaes aos processos de Sebastiano Serlio
(semi-circunferncias), Giuseppe Salviati (quartos-de-circunferncia) e Guil-
laume Philandrier (oitavos-de-circunferncia):
50
(espiral (xy 0 0) 10 (/ pi 2) pi (
*
pi 6) 0.8)
(espiral (xy 20 0) 10 (/ pi 2) (/ pi 2) (
*
pi 6) 0.8)
(espiral (xy 40 0) 10 (/ pi 2) (/ pi 4) (
*
pi 6) 0.8)
Os resultados esto representados na Figura 40.
7.18 Recurso na Natureza
Arecurso est presente eminmeros fenmenos naturais. As montanhas, por
exemplo, apresentam irregularidades que, quando observadas numa escala
apropriada, so em tudo idnticas a . . . montanhas. Um rio possui auentes e
cada auente idntico a . . . um rio. Uma vaso sanguneo possui ramicaes
e cada ramicao idntica a . . . um vaso sanguneo. Todas estas entidades
naturais constituem exemplos de estruturas recursivas.
Uma rvore outro bomexemplo de uma estrutura recursiva pois os ramos
de uma rvore so como pequenas rvores que emanam do tronco. Como se
pode ver da Figura 41, de cada ramo de uma rvoreemanam outras pequenas
rvores, num processo que se repete at se atingir uma dimenso suciente-
mente pequena em que aparecem outras estruturas como folhas, ores, frutos,
pinhas, etc.
Se, de facto, uma rvore possui uma estrutura recursiva ento dever ser
possvel construir rvores atravs de funes recursivas. Para testarmos esta
50
Note-se que se trata, to somente, de aproximaes. Os processos originais eram bastante
mais complexos.
138
Figura 40: Vrias espirais com razo de reduo de 0.8 e incremento de ngulo
de ,

2
e

4
, respectivamente.
Figura 41: A estrutura recursiva das rvores. Fotograa de Michael Bezzina.
139
(x
0
, y
0
)

c
f c f c
Figura 42: Parmetros de desenho de uma rvore.
teoria, vamos comear por considerar uma verso muito simplista de uma r-
vore, em que temos um tronco que, a partir de uma certa altura, se divide
em dois. Cada um destes subtroncos cresce fazendo um certo ngulo com o
tronco de onde emanou e com um comprimento que dever ser uma fraco
do comprimento desse tronco, tal como se apresenta na Figura 42. O caso de
paragem ocorre quando o comprimento do tronco se tornou to pequeno que,
em vez de se continuar a diviso, aparece simplesmente uma outra estrutura.
Para simplicar, vamos designar a extremidade de umramo por folha e iremos
represent-la com um pequeno crculo.
Para se darmos dimenses rvore, vamos considerar que a funo arvore
recebe, como argumento, as coordenadas da base da rvore, o comprimento
do tronco e o ngulo actual do tronco. Para a fase recursiva, teremos como
parmetros o ngulo de abertura alpha que o novo tronco dever fazer com
o actual e o factor de reduo f do comprimento do tronco. O primeiro passo
a computao do topo do tronco usando a funo +pol. Em seguida, dese-
nhamos o tronco desde a base at ao topo. Finalmente, testamos se o tronco
desenhado sucientemente pequeno. Se for, terminamos com o desenho de
umcrculo centrado no topo. Caso contrrio fazemos uma dupla recurso para
desenhar uma sub-rvore para a direita e outra para a esquerda. A denio
da funo ca:
(defun arvore (base comprimento angulo alfa f / topo)
(setq topo (+pol base comprimento angulo))
(ramo base topo)
(if (< comprimento 2)
(folha topo)
(progn
(arvore topo
(
*
comprimento f)
(+ angulo alfa)
alfa f)
(arvore topo
(
*
comprimento f)
(- angulo alfa)
alfa f))))
140
Figura 43: Uma rvore de comprimento 20, ngulo inicial

2
, abertura

8
e
factor de reduo 0.7.
(defun ramo (base topo)
(command "_.line" base topo ""))
(defun folha (topo)
(command "_.circle" topo 0.2))
Um primeiro exemplo de rvore gerado com a expresso
(arvore (xy 0 0) 20 (/ pi 2) (/ pi 8) 0.7)
est representado na Figura 43.
A Figura 44 apresenta outros exemplos em que se fez variar o ngulo de
abertura e o factor de reduo. A sequncia de expresses que as gerou foi a
seguinte:
(arvore (xy 0 0) 20 (/ pi 2) (/ pi 8) 0.6)
(arvore (xy 100 0) 20 (/ pi 2) (/ pi 8) 0.8)
(arvore (xy 200 0) 20 (/ pi 2) (/ pi 6) 0.7)
(arvore (xy 300 0) 20 (/ pi 2) (/ pi 12) 0.7)
Infelizmente, as rvores apresentadas so excessivamente simtricas: no
mundo natural literalmente impossvel encontrar simetrias perfeitas. Por
este motivo, convm tornar o modelo um pouco mais sosticado atravs da
introduo de parmetros diferentes para o crescimento dos troncos direita e
esquerda. Para isso, em vez de termos um s ngulo de abertura e um s fac-
tor de reduo de comprimento, vamos empregar dois, tal como se apresenta
na Figura 45.
A adaptao da funo arvore para lidar com os parmetros adicionais
trivial:
141
Figura 44: Vrias rvores geradas com diferentes ngulos de abertura e fac-
tores de reduo do comprimento dos ramos.
(x
0
, y
0
)

e
c
f
d
c
f
e
c
Figura 45: Parmetros de desenho de uma rvore comcrescimento assimtrico.
142
Figura 46: Vrias rvores geradas com diferentes ngulos de abertura e facto-
res de reduo do comprimento para os ramos esquerdo e direito.
(defun arvore (base comprimento angulo
alfa-e f-e alfa-d f-d
/ topo)
(setq topo (+pol base comprimento angulo))
(ramo base topo)
(if (< comprimento 2)
(folha topo)
(progn
(arvore topo
(
*
comprimento f-e)
(+ angulo alfa-e)
alfa-e f-e alfa-d f-d)
(arvore topo
(
*
comprimento f-d)
(- angulo alfa-d)
alfa-e f-e alfa-d f-d))))
A Figura 46 apresenta novos exemplos de rvores com diferentes ngulos
de abertura e factores de reduo dos ramos esquerdo e direito, geradas pelas
seguintes expresses:
(arvore (xy 0 0) 20 (/ pi 2) (/ pi 8) 0.6 (/ pi 8) 0.7)
(arvore (xy 100 0) 20 (/ pi 2) (/ pi 4) 0.7 (/ pi 16) 0.7)
(arvore (xy 200 0) 20 (/ pi 2) (/ pi 6) 0.6 (/ pi 16) 0.8)
As rvores geradas pela funo arvore so apenas um modelo muito
grosseiro da realidade. Embora existam sinais evidentes de que vrios fen-
menos naturais se podem modelar atravs de funes recursivas, a natureza
no to determinista quanto as nossas funes e, para que a modelao se
143
aproxime mais da realidade, fundamental incorporar tambm alguma alea-
toriedade. Esse ser o tema da prxima secco.
144
8 Atribuio
Como vimos, a atribuio a capacidade de estabelecermos uma associao
entre um nome e uma entidade. Como iremos ver, a atribuio permite, na re-
alidade, alterarmos a associao entre um nome e uma entidade, fazendo com
que o nome passe a estar associado a uma diferente entidade. Este conceito
introduz uma histria no valor do nome pois passamos a poder falar do valor
antes da atribuio e do valor depois da atribuio.
Nesta seco vamos discutir mais em profundidade o conceito de atribui-
o. Para motivar vamos comear por introduzir um tpico importante onde
a atribuio tem um papel primordial: a aleatoriedade.
8.1 Aleatoriedade
Desenhar implica tomar decises conscientes que conduzam a um objectivo
pretendido. Neste sentido, desenhar aparenta ser um processo racional onde
no h lugar para a aleatoriedade, a sorte ou a incerteza. De facto, nos dese-
nhos que temos feito at agora a racionalidade tem sido crucial pois o com-
putador exige uma especicao rigorosa do que se pretende, no permitindo
quaisquer ambiguidades. No entanto, sabido que um problema de desenho
frequentemente exige que o arquitecto experimente diferentes solues antes
de encontrar aquela que o satisfaz. Essa experimentao passa por empregar
alguma aleatoriedade no processo de escolha dos parmetros do desenho.
Assim, embora um desenho nal possa apresentar uma estrutura que espelha
uma inteno racional do arquitecto, o processo que conduziu a esse desenho
nal no necessariamente racional e pode ter passado por fases de ambigui-
dade e incerteza.
Quando a arquitectura se inspira na natureza surge um factor adicional
de aleatoriedade: em inmeros casos, a natureza intrinsecamente aleatria.
Essa aleatoriedade, contudo, no total e est sujeita a restries. Este facto
facilmente compreendido quando pensamos que embora no existam dois
pinheiros iguais, todos somos capazes de reconhecer o padro que caracte-
riza um pinheiro. Em todas as suas obras, a natureza combina estruturao
e aleatoriedade. Nalguns casos, como o crescimento de cristais, por exemplo,
h mais estruturao que aleatoriedade. Noutros casos, como no comporta-
mento de partculas subatmicas, h mais aleatoriedade que estruturao.
semelhana do que acontece na natureza, esta combinao de aleatoriedade e
estruturao claramente visvel em inmeras obras arquitecturais modernas.
Se pretendemos empregar computadores para o desenho e este desenho
pressupe aleatoriedade, ento teremos de ser capazes de a incorporar nos
nossos algoritmos. A aleatoriedade pode ser incorporada de inmeras formas
como, por exemplo:
A cor de um artefacto pode ser escolhida aleatoriamente.
O comprimento de uma parede pode ser um valor aleatrio entre deter-
minados limites.
145
A deciso de dividir uma rea ou mant-la ntegra pode ser tomada ale-
atoriamente.
A forma geomtrica a empregar para um determinado elemento arqui-
tectnico pode ser escolhida aleatoriamente.
8.2 Nmeros Aleatrios
Em qualquer dos casos anteriores, podemos reduzir a aleatoriedade escolha
de nmeros dentro de certos limites. Para uma cor aleatria, podemos gerar
aleatoriamente trs nmeros que representem os valores RGB
51
da cor. Para
um comprimento aleatrio, podemos gerar aleatoriamente um nmero dentro
dos limites desse comprimento. Para uma deciso lgica, podemos gerar ale-
atoriamente um nmero inteiro entre zero e um e decidir de um modo se o
nmero for zero e de outro modo se o nmero for um. Para uma escolha ale-
atria de entre um conjunto de alternativas podemos simplesmente gerar um
nmero aleatrio entre um e o nmero de elementos do conjunto e escolher a
alternativa correspondente ao nmero aleatrio gerado.
Estes exemplos mostram-nos que o fundamental conseguirmos gerar um
nmero aleatrio dentro de um certo intervalo. A partir dessa operao pode-
mos implementar todas as outras.
H dois processos fundamentais para se gerarem nmeros aleatrios. O
primeiro processo baseia-se na medio de processos fsicos intrnsecamente
aleatrios como seja o ruido electrnico ou o decaimento radioactivo. O se-
gundo processo baseia-se na utilizao de funes aritmticas que, a partir
de um valor inicial (denominado a semente), produzem uma sequncia de n-
meros aparentemente aleatrios, sendo cada nmero da sequncia gerado a
partir do nmero anterior. Neste caso dizemos que estamos perante um gera-
dor de nmeros pseudo-aleatrios. O termo pseudo justica-se pois, se repetirmos
o valor da semente original, repetiremos tambm a sequncia de nmeros de
gerados.
Muito embora umgerador de nmeros pseudo-aleatrios gere uma sequn-
cia de nmeros que, na verdade, no so aleatrios, ele possui duas importan-
tes vantagens:
Pode ser facilmente implementado usando uma qualquer linguagem de
programao, no necessitando de quaisquer mecanismos adicionais para
se obter a fonte de aleatoriedade.
frequente os nossos programas conterem erros. Para identicarmos a
causa do erro pode ser necessrio reproduzirmos exactamente as mes-
mas condies que deram origem ao erro. Para alm disso, depois da
correco do erro necessrio repetirmos novamente a execuo do pro-
grama para nos certicarmos que o erro no ocorre de novo. Infeliz-
mente, quando o comportamento de um programa depende de uma
51
RGB a abreviatura de Red-Green-Blue, um modelo de cores em que qualquer cor vista
como uma combinao das trs cores primrias vermelho, verde e azul.
146
sequncia de nmeros verdadeiramente aleatrios torna-se impossvel
reproduzir as condies de execuo: da prxima vez que executarmos
o programa, a sequncia de nmeros aleatrios ser quase de certeza di-
ferente.
Por estes motivos, de agora em diante vamos apenas considerar geradores
de nmeros pseudo-aleatrios que iremos abusivamente designar por gera-
dores de nmeros aleatrios. Um gerador deste tipo caracteriza-se por uma
funo f que, a partir de um argumento x
i
, produz um nmero x
i+1
= f(x
i
)
aparentemente no relacionado com x
i
. A semente do gerador o elemento x
0
da sequncia.
Falta agora encontramos uma funo f apropriada. Para isso, entre ou-
tras qualidades, exige-se que os nmeros gerados por f sejam equiprovveis,
i.e., todos os nmeros dentro de um determinado intervalo tm igual proba-
bilidade de serem gerados e que a sequncia de nmeros gerados tenha um
perodo to grande quanto possvel, i.e., que a sequncia dos nmeros gerados
s se comece a repetir ao m de muito tempo.
Tm sido estudadas inmeras funes com estas caractersticas. A mais
utilizada denominada funo geradora congruencial linear que da forma
52
x
i+1
= (ax
i
+ b) mod m
Por exemplo, se tivermos a = 25173, b = 13849, m = 65536 e comearmos
com uma semente qualquer, por exemplo, x
0
= 12345, obtemos a sequncia de
nmeros pseudo-aleatrios
53
2822, 11031, 21180, 42629, 27202, 49667, 50968,
33041, 37566, 43823, 2740, 43997, 57466, 29339, 39312, 21225, 61302, 58439,
12204, 57909, 39858, 3123, 51464, 1473, 302, 13919, 41380, 43405, 31722, 61131,
13696, 63897, 42982, 375, 16540, 25061, 24866, 31331, 48888, 36465, . . .
Podemos facilmente conrmar estes resultados usando o Lisp:
(defun proximo-aleatorio (ultimo-aleatorio)
(rem (+ (
*
25173 ultimo-aleatorio) 13849)
65536))
_$ (proximo-aleatorio 12345)
2822
_$ (proximo-aleatorio 2822)
11031
_$ (proximo-aleatorio 11031)
21180
Esta abordagem, contudo, implica que s podemos gerar um nmero ale-
atrio x
1+i
se nos recordarmos do nmero x
i
gerado imediatamente antes
52
O operador mod implementa o modulo, correspondente ao resto da diviso do primeiro
operando (o dividendo) pelo segundo operando (o divisor) e tendo o mesmo sinal do divisor.
O operador rem implementa o remainder, correspondente ao resto da diviso do dividendo pelo
divisor mas tendo o mesmo sinal do dividendo. Nem todas as linguagens implementam ambos
os operadores. A linguagem Auto Lisp apenas implementa o operador rem.
53
Na verdade, esta sequncia no sucientemente aleatria pois existe um padro que se
repete continuamente. Consegue descobri-lo?
147
para o podermos dar como argumento funo proximo-aleatorio. In-
felizmente, o momento e o ponto do programa em que podemos precisar de
um novo nmero aleatrio pode ocorrer muito mais tarde e muito mais longe
do que o momento e o ponto do programa em que foi gerado o ltimo n-
mero aleatrio, o que complica substancialmente a escrita do programa. Seria
prefervel que, ao invs da funo proximo-aleatorio que depende do l-
timo valor gerado x
i
, tivssemos uma funo aleatorio que no precisasse
de receber o ltimo nmero gerado para conseguir gerar o prximo nmero.
Assim, em qualquer ponto do programa em que precisssemos de gerar um
novo nmero aleatrio, limitvamo-nos a invocar a funo aleatorio sem
termos de nos recordar do ltimo nmero gerado. Partindo do mesmo valor
da semente, teriamos:
_$ (aleatorio)
2822
_$ (aleatorio)
11031
_$ (aleatorio)
21180
8.3 Estado
A funo aleatorio apresenta um comportamento diferente do das funes
que vimos at agora. At este momento, todas as funes que tnhamos de-
nido comportavam-se como as funes matemticas tradicionais: dados argu-
mentos, a funo produz resultados e, mais importante, dados os mesmos ar-
gumentos, a funo produz sempre os mesmos resultados. Por exemplo, inde-
pendentemente do nmero de vezes que invocamos a funo quadrado, para
um dado argumento ela ir sempre produzir o quadrado desse argumento.
A funo aleatorio diferente de todas as outras pois, para alm de no
precisar de argumentos, ela produz um resultado diferente de cada vez que
invocada.
Do ponto de vista matemtico, uma funo sem parmetros no tem nada
de anormal: precisamente aquilo que se designa por uma constante. De facto,
tal como escrevemos sincos x para designar sin(cos(x)), tambm escrevemos
sin para designar sin(()), onde se v que pode ser interpretado como uma
funo sem argumentos.
Do ponto de vista matemtico, uma funo que produz resultados diferen-
tes a cada invocao no tem nada de normal: uma aberrao pois, de acordo
com a denio matemtica de funo, esse comportamento no possvel. E,
no entanto, precisamente este o comportamento que gostaramos de ter na
funo aleatorio.
Para se obter o pretendido comportamento necessrio introduzir o con-
ceito de estado. Dizemos que uma funo tem estado quando o seu comporta-
mento depende da sua histria, i.e., das suas invocaes anteriores. A funo
aleatrio um exemplo de uma funo com estado mas h inmeros ou-
tros exemplos no mundo real. Uma conta bancria tambm tem um estado
que depende de todas as transaces anteriores que lhe tiverem sido feitas. O
148
depsito de combustvel de um carro tambm tem um estado que depende
dos enchimentos e dos trajectos realizados.
Para que uma funo possa ter histria necessrio que tenha memria, i.e.,
que se possa recordar de acontecimentos passados para assim poder inuen-
ciar os resultados futuros. At agora, vimos que o operador setq nos permitia
denir associaes entre nomes e valores, mas o que ainda no tnhamos discu-
tido a possibilidade desse operador modicar associaes, i.e., alterar o valor
que estava associado a um determinado nome. esta possibilidade que nos
permite incluir memria nas nossas funes.
No caso da funo aleatorio vimos que a memria que nos interessa
saber qual foi o ltimo nmero aleatrio gerado. Imaginemos ento que
tnhamos uma associao entre o nome ultimo-aleatorio-gerado e esse
nmero. No momento inicial, naturalmente, esse nome dever estar associado
semente da sequncia de nmeros aleatrios. Para isso, denimos:
_$ (setq ultimo-aleatorio-gerado 12345)
De seguida, j podemos denir a funo aleatorio que no s usa
o ltimo valor associado quele nome como actualiza essa associao com o
novo valor gerado, i.e.:
54
(defun aleatorio ()
(setq ultimo-aleatorio-gerado
(proximo-aleatorio ultimo-aleatorio-gerado)))
_$ (aleatorio)
2822
_$ (aleatorio)
11031
Como se v, de cada vez que a funo aleatorio invocada, o valor as-
sociado a ultimo-aleatorio-gerado actualizado, permitindo assim in-
uenciar o futuro comportamento da funo. Obviamente, em qualquer mo-
mento, podemos re-iniciar a sequncia de nmeros aleatrios simplesmente
repondo o valor da semente:
_$ (aleatorio)
21180
_$ (aleatorio)
42629
_$ (setq ultimo-aleatorio-gerado 12345)
12345
_$ (aleatorio)
2822
_$ (aleatorio)
11031
_$ (aleatorio)
21180
54
Note-se que o operador setq, para alm de estabelecer uma associao entre um nome e
um valor devolve o valor que cou associado.
149
8.4 Estado Local e Estado Global
Vimos anteriormente que uma funo pode ter variveis locais bastando, para
isso, a sua indicao a seguir aos parmetros da funo. Cada varivel local
possui um nome que apenas visvel para a funo que a contm.
55
Acon-
tece que no caso da funo aleatorio, ela usa uma varivel denominada
ultimo-aleatorio-gerado que no referida na lista de parmetros da
funo. Consequentemente, no uma varivel local, dizendo-se ento que
uma varivel livre.
Quando uma varivel livre visvel de todos os lados, tal como acontece
comultimo-aleatorio-gerado, dizemos que se trata de uma varivel glo-
bal. Ao conjunto de todas as variveis globais de umprograma chama-se estado
global pois, em cada instante, elas determinam o estado do programa.
Uma varivel global , potencialmente, uma enorme fonte de problemas
pois pode ser alterada em qualquer momento e a partir de qualquer ponto
do programa. Quando essa alterao incorrecta pode ser muito dicil saber
quando e onde que o erro foi cometido.
No entanto, nalguns casos como o da funo aleatorio, a nica forma de
podermos dar memria s funes atravs de variveis globais. De facto, em
Auto Lisp, as variveis locais possuem durao dinmica, i.e., apenas existem
enquanto a funo que as introduz est a ser invocada (e existem ocorrncias
diferentes dessas variveis para diferentes invocaes da funo). Por este mo-
tivo, em Auto Lisp, uma varivel local no pode nunca ser usada para manter
uma memria que dure mais do que a invocao da funo. Isto implica que
no possvel termos estado local em Auto Lisp, i.e., no possvel termos um
conjunto de variveis que descrevem o estado de uma funo mas que no so
visiveis globalmente.
56
Por estes motivos, em Auto Lisp, a nica possibilidade que temos de dar
memria s nossas funes atravs da utilizao de variveis globais. Pelos
problemas apontados devemos, contudo, ter extremo cuidado coma utilizao
de variveis globais e devemos estar alertas para a possibilidade de ocorrerem
conitos de nomes, em que duas funes independentes pretendem denir
uma mesma varivel global.
57
Para evitar este ltimo problema, as nossas
variveis globais devem ter nomes perfeitamente explcitos e com pouca pro-
babilidade de aparecerem repetidos em contextos diferentes.
8.5 Escolhas Aleatrias
Se observarmos a denio da funo proximo-aleatorio constatamos que
a sua ltima operao computar o resto da diviso por 65536, o que implica
que a funo produz sempre valores entre 0 e 65535. Embora (pseudo) ale-
atrios, estes valores esto contidos num intervalo que s muito excepcional-
55
Esta armao no inteiramente verdade para o Auto Lisp. Mais frente explicaremos
aquilo que verdadeiramente acontece no caso do Auto Lisp.
56
H outros dialectos de Lisp e muitas outras linguagens de programao que permitem o
estado local.
57
Alguns dialectos de Lisp possuem mecanismos que permitem evitar estes conitos. O Auto
Lisp, infelizmente, no possui qualquer destes mecanismos.
150
mente ser til. Na realidade, muito mais frequente precisarmos de nmeros
aleatrios contidos em intervalos muito mais pequenos. Por exemplo, se pre-
tendermos simular o lanar de uma moeda ao ar, estaremos interessados em
ter apenas os nmeros aleatrios 0 ou 1, representando caras ou coroas.
Tal como os nmeros aleatrios que produzimos so limitados ao inter-
valo [0, 65536[ pela obteno do resto da diviso por 65536, tambm agora
podemos voltar aplicar a mesma operao para produzir um intervalo mais
pequeno. Assim, no caso do lanamento de uma moeda ao ar podemos sim-
plesmente usar a funo aleatorio para gerar um nmero aleatrio e, de
seguida, aplicamos-lhe o resto da diviso por dois. No caso geral, em que
pretendemos nmeros aleatrios no intervalo [0, x[, aplicamos o resto da di-
viso por x. Assim, podemos denir uma nova funo que gera um nmero
aleatrio entre zero e o seu parmetro e que, por tradio, iremos baptizar de
random:
(defun random (x)
(rem (aleatorio) x))
Note-se que a funo random nunca deve receber um argumento maior
que 65535 pois isso faria a funo perder a caracterstica da equiprobabilidade
dos nmeros gerados: todos os nmeros superiores a 65535 tero probabili-
dade zero de ocorrerem.
58
agora possvel simularmos inmeros fenmenos aleatrios como, por
exemplo, o lanar de uma moeda:
(defun cara-ou-coroa ()
(if (= (random 2) 0)
"cara"
"coroa"))
Infelizmente, quando testamos repetidamente a nossa funo, o seu com-
portamento parece muito pouco aleatrio:
_$ (cara-ou-coroa)
"cara"
_$ (cara-ou-coroa)
"coroa"
_$ (cara-ou-coroa)
"cara"
_$ (cara-ou-coroa)
"coroa"
_$ (cara-ou-coroa)
"cara"
_$ (cara-ou-coroa)
"coroa"
Na realidade, os resultados que obtemos so uma repetio sistemtica do
par cara/coroa, o que mostra que a expresso (random 2) se limita a gerar
a sequncia:
58
Na verdade, o limite superior deve ser bastante inferior ao limite da funo aleatorio
para manter a equiprobabilidade dos resultados.
151
01010101010101010101010101010101010101010110101010101010101
O mesmo fenmeno ocorre para outros limites do intervalo de gerao.
Por exemplo, a expresso (random 4) deveria gerar um nmero aleatrio no
conjunto 0, 1, 2, 3 mas a sua aplicao repetida gera a seguinte sequncia de
nmeros:
01230123012301230123012301230123012301230123012301230123012
Embora a equiprobabilidade dos nmeros seja perfeita, evidente que no
h qualquer aleatoriedade.
O problema das duas sequncias anteriores est no facto de terem um pe-
rodo muito pequeno. O perodo nmero de elementos que so gerados antes
de o gerador entrar em ciclo e voltar a repetir os mesmos elementos que gerou
anteriormente. Obviamente, quanto maior for o perodo, melhor o gerador
de nmeros aleatrios e, neste sentido, o gerador que apresentmos de baixa
qualidade.
Enormes quantidades de esforo tm sido investidas na procura de bons
geradores de nmeros aleatrios e embora os melhores sejamproduzidos usando
mtodos bastante mais sosticados do que os que empregmos at agora, tam-
bm possvel encontrar um bom gerador congruencial linear desde que se
faa uma judiciosa escolha dos seus parmetros. De acordo com [?, ?, ?, ?, ?, ?],
o gerador congruencial linear
x
i+1
= (ax
i
+ b) mod m
pode constituir um bom gerador pseudo-aleatrio desde que tenhamos a =
16807, b = 0 e m = 2
31
1 = 2147483647. Uma traduo directa da denio
matemtica produz a seguinte funo Lisp:
(defun proximo-aleatorio (ultimo-aleatorio)
(rem (
*
16807 ultimo-aleatorio)
2147483647))
Infelizmente, quando testamos a funo aleatorio, obtemos resultados
bizarros: 64454845, 960821323, 553057299, 924795749, 444490781, . . . . Sendo
o parmetro ultimo-aleatorio inicialmente positivo e sendo o produto e
o resto da diviso obtidos usando operandos positivos, o resultado teria ne-
cessariamente de ser no-negativo. Uma vez que existem valores negativos
na sequncia isso sugere que est a ocorrer o mesmo fenmeno que discuti-
mos na seco 3.10: overow, i.e., o resultado da multiplicao , por vezes, um
nmero demasiado grande para a capacidade de representao do Auto Lisp.
Para resolver este problema, inventou-se um algoritmo (ver [?, ?]) capaz de
computar os nmeros sem exceder a capacidade da mquina, desde que esta
seja capaz de representar todos os inteiros no intervalo [2
31
, 2
31
1], ou seja,
[2147483648, 2147483647] que precisamente a gama de valores represent-
veis em Auto Lisp. O algoritmo baseia-se simplesmente em garantir que todos
os valores intermdios do clculo so sempre representveis pelo Auto Lisp.
152
(defun proximo-aleatorio (ultimo-aleatorio / teste)
(setq teste (- (
*
16807 (rem ultimo-aleatorio 127773))
(
*
2836 (/ ultimo-aleatorio 127773))))
(setq ultimo-aleatorio
(if (> teste 0)
teste
(+ teste 2147483647))))
Esta denio tem a vantagem de permitir gerar aleatoriamente todos os
inteiros representveis pela linguagem. Usando esta denio da funo, a
repetida avaliao da expresso (random 2) produz a sequncia:
01001010001011110100100011000111100110110101101111000011110
e, para a expresso (random 4), produz:
21312020300221331333233301112313001012333020321123122330222
razoavelmente evidente que qualquer das sequncias geradas tem agora
um perodo demasiado grande para se conseguir detectar qualquer padro de
repetio. De ora em diante, ser esta a denio de proximo-aleatorio
que iremos empregar.
8.5.1 Nmeros Aleatrios Fraccionrios
O processo de gerao de nmeros aleatrios que implementmos apenas
capaz de gerar nmeros aleatrios do tipo inteiro. No entanto, tambm fre-
quente precisarmos de gerar nmeros aleatrios fraccionrios, por exemplo,
no intervalo [0, 1[.
Para combinar estes dois requisitos, usual no mundo do Lisp que a funo
random receba o limite superior de gerao x e o analise para determinar se
inteiro ou real, devolvendo um valor aleatrio adequado em cada caso. Para
isso, no preciso mais do que mapear o intervalo de gerao de inteiros que,
como vimos, [0, 2147483647[, no intervalo [0, x[. A implementao trivial:
59
(defun random (x)
(if (realp x)
(
*
x (/ (aleatorio) 2147483647.0))
(rem (aleatorio) x)))
8.5.2 Nmeros Aleatrios num Intervalo
Se, ao invs de gerarmos nmeros aleatrios no intervalo [0, x[, preferirmos
gerar nmeros aleatrios no intervalo [x
0
, x
1
[ ento basta-nos gerar um n-
mero aleatrio no intervalo [0, x
1
x
0
[ e somar-lhe x
0
. A funo random-[]
implementa esse comportamento:
(defun random-[] (x0 x1)
(+ x0 (random (- x1 x0))))
59
Esta funo usa o reconhecedor universal realp que foi denido na seco 6.11.
153
Tal como a funo random, tambm random-[] produz um valor real no
caso de algum dos limites ser real.
Para visualizarmos um exemplo de utilizao desta funo, vamos recupe-
rar a funo arvore que modelava uma rvore, cuja denio era:
(defun arvore (base comprimento angulo
alfa-e f-e alfa-d f-d
/ topo)
(setq topo (+pol base comprimento angulo))
(ramo base topo)
(if (< comprimento 2)
(folha topo)
(progn
(arvore topo
(
*
comprimento f-e)
(+ angulo alfa-e)
alfa-e f-e alfa-d f-d)
(arvore topo
(
*
comprimento f-d)
(- angulo alfa-d)
alfa-e f-e alfa-d f-d))))
Para incorporarmos alguma aleatoriedade neste modelo de rvore pode-
mos considerar que os ngulos de abertura dos ramos e os factores de redu-
o de comprimento desses ramos no possuem valores constantes ao longo
da recurso, antes variando dentro de certos limites. Assim, em vez de nos
preocuparmos em ter diferentes aberturas e factores para o ramo esquerdo e
direito, teremos simplesmente variaes aleatrias em ambos:
(defun arvore (base comprimento angulo
min-alfa max-alfa min-f max-f
/ topo)
(setq topo (+pol base comprimento angulo))
(ramo base topo)
(if (< comprimento 2)
(folha topo)
(progn
(arvore topo
(
*
comprimento (random-[] min-f max-f))
(+ angulo (random-[] min-alfa max-alfa))
min-alfa max-alfa min-f max-f)
(arvore topo
(
*
comprimento (random-[] min-f max-f))
(- angulo (random-[] min-alfa max-alfa))
min-alfa max-alfa min-f max-f))))
Usando esta nova verso, podemos gerar inmeras rvores semelhantes
e, contudo, sucientemente diferentes para parecerem bastante mais naturais.
As rvores apresentadas na Figura 47 foram geradas usando exactamente os
mesmos parmetros de crescimento:
154
Figura 47: Vrias rvores geradas com ngulos de abertura aleatrios no in-
tervalo [

2
,

16
[ e factores de reduo do comprimento aleatrios no intervalo
[0.6, 0.9[.
(arvore (xy 0 0) 20 (/ pi 2) (/ pi 16) (/ pi 4) 0.6 0.9)
(arvore (xy 150 0) 20 (/ pi 2) (/ pi 16) (/ pi 4) 0.6 0.9)
(arvore (xy 300 0) 20 (/ pi 2) (/ pi 16) (/ pi 4) 0.6 0.9)
(arvore (xy 0 150) 20 (/ pi 2) (/ pi 16) (/ pi 4) 0.6 0.9)
(arvore (xy 150 150) 20 (/ pi 2) (/ pi 16) (/ pi 4) 0.6 0.9)
(arvore (xy 300 150) 20 (/ pi 2) (/ pi 16) (/ pi 4) 0.6 0.9)
Exerccio 8.5.1 As rvores produzidas pelas funo arvore so pouco realista pois
so totalmente bidimensionais, com troncos que so simples linhas e folhas que so
pequenas circunferncias. O clculo das coordenadas dos ramos e folhas tambm bi-
dimensional, assentando sobre coordenadas polares que so dadas pelos parmetros
comprimento e angulo.
Pretende-se que redena as funes ramo, folha e arvore de modo a aumentar
o realismo das rvores geradas.
Para simplicar, considere que as folhas podem ser simuladas por pequenas esfe-
ras e que os ramos podem ser simulados por troncos de cone, cujo raio da base 10%
do comprimento do tronco e cujo raio do topo 90% do raio da base.
Para que a gerao de rvores passe a ser verdadeiramente tridimensional, rede-
na tambm a funo arvore de modo a que o topo de cada ramo seja um ponto em
coordenadas esfricas escolhidas aleatoriamente a partir da base do ramo. Isto implica
que a funo rvore, ao invs de ter dois parmetros para o comprimento e o ngulo
das coordenadas polares, precisar de ter trs, para o comprimento, a longitude e a
co-latitude. Do mesmo modo, ao invs de receber os quatro limites para a gerao de
comprimentos e ngulos aleatrios, precisar de seis limites para os trs parmetros.
Experimente diferentes argumentos para a sua redenio da funo arvore de
modo a gerar imagens como a seguinte:
155
8.6 Planeamento Urbano
As cidades constituem um bom exemplo de combinao entre estruturao e
aleatoriedade. Embora muitas das cidades mais antigas aparentem ter uma
forma catica resultante do seu desenvolvimento no ter sido planeado, a ver-
dade que desde muito cedo se sentiu a necessidade de estruturar a cidade de
modo a facilitar a sua utilizao e o seu crescimento, sendo conhecidos exem-
plos de cidades planeadas desde 2600 antes de Cristo.
Embora haja bastantes variaes, as duas formas mais usuais de planear
uma cidade so atravs do plano ortogonal ou atravs do plano circular. No
plano ortogonal, as avenidas so rectas e fazem ngulos rectos entre si. No
plano circular as avenidas principais convergem numa praa central e as ave-
nidas secundrios desenvolvem-se em crculos concntricos em torno deste
ponto, acompanhando o crescimento da cidade. A Figura 48 apresenta um
bom exemplo de uma cidade essencialmente desenvolvida a partir de planos
ortogonais. Nesta seco vamos explorar a aleatoriedade para produzir varia-
es em torno destes planos.
Num plano ortogonal, a cidade organiza-se em termos de quarteires, em
que cada quarteiro assume uma forma quadrada ou rectangular e pode conter
vrios edifcios. Para simplicar, vamos assumir que cada quarteiro ser de
forma quadrada e ir conter um nico edifcio. Cada edifcio ter uma largura
determinada pela largura do quarteiro e uma altura mxima imposta. Os
edifcios sero separados uns dos outros por ruas com uma largura xa.
Para estruturarmos a funo que constri a cidade em malha ortogonal,
vamos decompor o processo na construo de sucessivas ruas. A construo
de cada rua ser ento decomposta na construo dos sucessivos prdios. As-
sim, teremos de parameterizar a funo com o nmero de ruas a construir na
156
Figura 48: Vista area da cidade de New York nos Estados Unidos. Fotograa
de Art Siegel.
cidade e com o nmero de prdios por rua. Para alm disso iremos necessi-
tar de saber as coordenadas do ponto p onde se comea a construir a cidade,
a largura e a altura de cada prdio, respectivamente, l-predio e a-predio
e, nalmente, a largura da rua l-rua. A funo ir construir uma faixa de
prdios seguido de uma rua e, recursivamente, construir as restantes faixas
de prdios e ruas no ponto correspondente faixa seguinte. Para simplicar,
vamos assumir que as ruas estaro alinhadas com os eixos x e y, pelo que cada
nova rua corresponde a um deslocamento ao longo do eixo y e cada novo pr-
dio corresponde a um deslocamento ao longo do eixo x. Assim, temos:
(defun malha-predios (p ruas predios l-predio a-predio l-rua)
(if (= ruas 0)
nil
(progn
(rua-predios p predios l-predio a-predio l-rua)
(malha-predios (+xy p 0 (+ l-predio l-rua))
(1- ruas)
predios
l-predio
a-predio
l-rua))))
Para a construo das ruas com prdios, o racioccio idntico: colocamos
um prdio nas coordenadas correctas e, recursivamente, colocamos os restan-
tes prdios aps o deslocamento correspondente. A seguinte funo imple-
menta este processo:
157
Figura 49: Uma urbanizao em malha ortogonal com cem edifcios todos da
mesma altura.
(defun rua-predios (p predios l-predio a-predio l-rua)
(if (= predios 0)
nil
(progn
(predio p l-predio a-predio)
(rua-predios (+xy p (+ l-predio l-rua) 0)
(1- predios)
l-predio
a-predio
l-rua))))
Finalmente, precisamos de denir a funo que cria um prdio. Para sim-
plicar, vamos model-lo como um paralelippedo:
(defun predio (p l-predio a-predio)
(command "_.box" p (+xyz p l-predio l-predio a-predio)))
Comestas trs funes j podemos experimentar a construo de uma nova
urbanizao. Por exemplo, a seguinte expresso cria um arranjo de dez ruas
com dez prdios por rua:
(malha-predios (xyz 0 0 0) 10 10 100 400 40)
O resultado est representado na Figura 49.
Como bvio pela Figura 49, a urbanizao produzida pouco elegante
pois falta-lhe alguma da aleatoriedade que caracteriza as cidades.
158
Figura 50: Uma urbanizao em malha ortogonal com cem edifcios com altu-
ras aleatrias.
Para incorporarmos essa aleatoriedade vamos comear por considerar que
a altura dos prdios pode variar aleatoriamente entre a altura mxima dada e
um dcimo dessa altura. Para isso, redenimos a funo predio:
(defun predio (p l-predio a-predio)
(command "_.box"
p
(+xyz p
l-predio
l-predio
(
*
(random-[] 0.1 1.0) a-predio))))
Usando exactamente os mesmos parmetros anteriores em duas avaliaes
sucessivas da mesma expresso, conseguimos agora construir as urbanizaes
esteticamente mais apelativas representadas nas Figuras 50 e 51.
Exerccio 8.6.1 As urbanizaes produzidas pelas funes anteriores no apresentam
variabilidade suciente pois os edifcios tm todos a mesma forma. Para melhorar
a qualidade esttica da urbanizao pretende-se empregar diferentes funes para a
construo de diferentes tipos de edifcios: a funo predio0 dever construir um
paralelippedo de altura aleatria tal como anteriormente e a funo predio1 dever
construir uma torre cilndrica de altura aleatria e contida no espao de umquarteiro.
Dena estas duas funes.
Exerccio 8.6.2 Pretende-se que use as duas funes predio0 e predio1 denidas
no exerccio anterior para a redenio da funo predio de modo a que esta, alea-
toriamente, construa prdios diferentes. A urbanizao resultante dever ser consti-
159
Figura 51: Uma urbanizao em malha ortogonal com cem edifcios com altu-
ras aleatrias.
tuda aproximadamente por 20% de torres circulares e 80% de prdios rectangulares,
tal como exemplicado na imagem seguinte:
Exerccio 8.6.3 As cidades criadas nos exerccios anteriores apenas permitem dois ti-
pos de edifcios: torres paralelipipdicas ou torres cilndricas. Contudo, quando ob-
160
Figura 52: Vista de alguns prdios de Manhattan. Fotograa de James K. Po-
ole.
servamos uma cidade real como a apresentada na Figura 52, vericamos que existem
prdios com muitas outras formas pelo que, para aumentarmos o realismo das nossas
simulaes, teremos de implementar um vasto nmero de funes, cada uma capaz
de construir um edifcio diferente.
Felizmente, uma observao atenta da Figura 52 mostra que, na verdade, muitos
dos prdios seguem um padro e podem ser modelado por paralelippedos sobrepos-
tos com dimenses aleatrias mas sempre sucessivamente mais pequenos em funo
da altura, algo que podemos facilmente implementar com uma nica funo.
Considere que este modelo de edifcio parameterizado pelo nmero de blocos
sobrepostos pretendidos, pelas coordenadas do primeiro bloco e pelo comprimento,
largura e altura do edifcio. O bloco de base tem exactamente o comprimento e lar-
gura especicados mas a sua altura dever estar entre 20% e 80% da altura total do
edifcio. Os blocos seguintes esto centrados sobre o bloco imediatamente abaixo e
possuem um comprimento e largura que esto entre 70% e 100% dos parmetros cor-
respondentes no bloco imediatamente abaixo. A altura destes blocos dever ser entre
20% e 80% da altura restante do edifcio. A imagem seguinte mostra alguns exemplos
deste modelo de edifcios:
161
Com base nesta especicao, dena a funo predio-blocos e use-a para re-
denir a funo predio0 de modo a que sejam gerados prdios com um nmero ale-
atrio de blocos sobrepostos. Com esta redenio, a funo malha-predios dever
ser capaz de gerar urbanizaes semelhantes imagem seguinte, em que se empregou
para cada prdio um nmero de blocos entre 1 e 6:
Exerccio 8.6.4 Emgeral, as cidades possuemumncleo de edifcios relativamente al-
tos no centro e, medida que nos afastamos para a periferia, a altura tende a diminuir,
sendo este fenmeno perfeitamente visvel na Figura 48.
A variao da altura dos edifcios pode ser modelada por diversas funes mate-
162
mticas mas, neste exerccio, pretende-se que empregue uma distribuio Gaussiana
bi-dimensional dada por
f(x, y) = e

(
xxo
x
)
2
+(
yyo
y
)
2

em que f o factor de ponderao da altura, (x


0
, y
0
) so as coordenadas do ponto
mais alto da superfcie Gaussiana e
0
e
1
so os factores que afectam o alargamento
bi-dimensional dessa superfcie. Para simplicar, assuma que o centro da cidade ca
nas coordenadas (0, 0) e que
x
=
y
= 25l, sendo l a largura do edifcio. A imagem
seguinte mostra o aspecto de uma destas urbanizaes:
Incorpore esta distribuio no processo de construo de cidades para produzir
cidades mais realistas.
Exerccio 8.6.5 Frequentemente, as cidades possuem mais do que um ncleo de edif-
cios altos. Estes ncleos encontram-se separados uns dos outros por zonas de edifcios
menos altos. Tal como no exerccio anterior, cada ncleo de edifcios pode ser mode-
lado por uma distribuio Gaussiana. Admitindo a independncia dos vrios ncleos,
a altura dos edifcios pode ser modelada por distribuies Gaussianas sobrepostas,
i.e., em cada ponto, a altura do edifcio ser o mximo das alturas das distribuies
Gaussianas dos vrios ncleos.
Utilize a abordagem anterior para exemplicar a modelao de uma cidade com
trs ncleos de arranha-cus, semelhana do que se apresenta na imagem se-
guinte:
163
164