antónio menezes leitão fevereiro 2007 - autenticação · 2 sintaxe, semântica e pragmática 13...

178
Introdução à Programação com AutoLisp António Menezes Leitão Fevereiro 2007

Upload: docong

Post on 26-Jan-2019

218 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Introdução à Programação com AutoLisp

António Menezes Leitão

Fevereiro 2007

Page 2: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Conteúdo

1 Programação 71.1 Linguagens de Programação . . . . . . . . . . . . . . . . . . . 101.2 Lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111.3 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2 Sintaxe, Semântica e Pragmática 132.1 Sintaxe e Semântica do Lisp . . . . . . . . . . . . . . . . . . . 142.2 O Avaliador . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

3 Elementos da Linguagem 153.1 Elementos primitivos . . . . . . . . . . . . . . . . . . . . . . . 16

3.1.1 Números . . . . . . . . . . . . . . . . . . . . . . . . . . 163.1.2 Cadeias de Caracteres . . . . . . . . . . . . . . . . . . 17

3.2 Combinações . . . . . . . . . . . . . . . . . . . . . . . . . . . 183.3 Indentação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203.4 Avaliação de Combinações . . . . . . . . . . . . . . . . . . . . 223.5 Operadores de Strings . . . . . . . . . . . . . . . . . . . . . . 233.6 Definição de Funções . . . . . . . . . . . . . . . . . . . . . . . 243.7 Símbolos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273.8 Avaliação de Símbolos . . . . . . . . . . . . . . . . . . . . . . 283.9 Funções de Múltiplos Parâmetros . . . . . . . . . . . . . . . . 293.10 Encadeamento de Funções . . . . . . . . . . . . . . . . . . . . 303.11 Funções Pré-Definidas . . . . . . . . . . . . . . . . . . . . . . 303.12 Aritmética de Inteiros em Auto Lisp . . . . . . . . . . . . . . 333.13 Aritmética de Reais em Auto Lisp . . . . . . . . . . . . . . . 363.14 Símbolos e Avaliação . . . . . . . . . . . . . . . . . . . . . . . 38

4 Combinação de Dados 404.1 Coordenadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404.2 Pares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414.3 Operações com Coordenadas . . . . . . . . . . . . . . . . . . 434.4 Abstracção de Dados . . . . . . . . . . . . . . . . . . . . . . . 444.5 Coordenadas Tri-Dimensionais . . . . . . . . . . . . . . . . . 474.6 Coordenadas Bi- e Tri-Dimensionais . . . . . . . . . . . . . . 514.7 A Notação de Lista . . . . . . . . . . . . . . . . . . . . . . . . 544.8 Átomos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564.9 Tipos Abstractos . . . . . . . . . . . . . . . . . . . . . . . . . . 574.10 Coordenadas em AutoCad . . . . . . . . . . . . . . . . . . . . 59

1

Page 3: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

4.11 Coordenadas Polares . . . . . . . . . . . . . . . . . . . . . . . 604.12 A função command . . . . . . . . . . . . . . . . . . . . . . . . 634.13 Variantes de Comandos . . . . . . . . . . . . . . . . . . . . . 714.14 Ângulos em Comandos . . . . . . . . . . . . . . . . . . . . . . 724.15 Efeitos Secundários . . . . . . . . . . . . . . . . . . . . . . . . 744.16 A Ordem Dórica . . . . . . . . . . . . . . . . . . . . . . . . . . 754.17 Parameterização de Figuras Geométricas . . . . . . . . . . . 794.18 Documentação . . . . . . . . . . . . . . . . . . . . . . . . . . . 844.19 Depuração . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

4.19.1 Erros Sintáticos . . . . . . . . . . . . . . . . . . . . . . 884.19.2 Erros Semânticos . . . . . . . . . . . . . . . . . . . . . 90

5 Modelação Tridimensional 925.1 Sólidos Tridimensionais Pré-Definidos . . . . . . . . . . . . . 925.2 Modelação de Colunas Dóricas . . . . . . . . . . . . . . . . . 97

6 Expressões Condicionais 996.1 Expressões Lógicas . . . . . . . . . . . . . . . . . . . . . . . . 1016.2 Valores Lógicos . . . . . . . . . . . . . . . . . . . . . . . . . . 1016.3 Predicados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1016.4 Predicados Aritméticos . . . . . . . . . . . . . . . . . . . . . . 1026.5 Operadores Lógicos . . . . . . . . . . . . . . . . . . . . . . . . 1026.6 Predicados com número variável de argumentos . . . . . . . 1036.7 Predicados sobre Cadeias de Caracteres . . . . . . . . . . . . 1036.8 Predicados sobre Símbolos . . . . . . . . . . . . . . . . . . . . 1046.9 Predicados sobre Listas . . . . . . . . . . . . . . . . . . . . . . 1046.10 Reconhecedores . . . . . . . . . . . . . . . . . . . . . . . . . . 1056.11 Reconhecedores Universais . . . . . . . . . . . . . . . . . . . 1066.12 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

7 Estruturas de Controle 1087.1 Sequenciação . . . . . . . . . . . . . . . . . . . . . . . . . . . 1097.2 Invocação de Funções . . . . . . . . . . . . . . . . . . . . . . . 1107.3 Variáveis Locais . . . . . . . . . . . . . . . . . . . . . . . . . . 1127.4 Atribuição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1147.5 Variáveis Globais . . . . . . . . . . . . . . . . . . . . . . . . . 1167.6 Variáveis Indefinidas . . . . . . . . . . . . . . . . . . . . . . . 1187.7 Proporções de Vitrúvio . . . . . . . . . . . . . . . . . . . . . . 1197.8 Selecção . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1227.9 Selecção Múltipla—A Forma cond . . . . . . . . . . . . . . . 124

2

Page 4: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

7.10 Selecção nas Proporções de Vitrúvio . . . . . . . . . . . . . . 1267.11 Operações com Coordenadas . . . . . . . . . . . . . . . . . . 1307.12 Coordenadas Cilíndricas . . . . . . . . . . . . . . . . . . . . . 1357.13 Coordenadas Esféricas . . . . . . . . . . . . . . . . . . . . . . 1387.14 Recursão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1397.15 Depuração de Programas Recursivos . . . . . . . . . . . . . . 146

7.15.1 Trace . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1477.16 Templos Dóricos . . . . . . . . . . . . . . . . . . . . . . . . . . 1517.17 A Ordem Jónica . . . . . . . . . . . . . . . . . . . . . . . . . . 1637.18 Recursão na Natureza . . . . . . . . . . . . . . . . . . . . . . 171

3

Page 5: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

1 Programação

A transmissão de conhecimento é um dos problemas que desde cedo pre-ocupou a humanidade. Sendo o homem capaz de acumular conhecimentoao longo de toda a sua vida, é com desânimo que enfrenta a ideia de que,com a morte, todo esse conhecimento se perca.

Para evitar esta perda, a humanidade inventou toda uma série de me-canismos de transmissão de conhecimento. O primeiro, a transmissão oral,consiste na transmissão do conhecimento de uma pessoa para um grupo re-duzido de outras pessoas, de certa forma transferindo o problema da perdade conhecimento para a geração seguinte. O segundo, a transmissão es-crita, consiste em registar em documentos o conhecimento que se pretendetransmitir. Esta forma tem a grande vantagem de, por um lado, poder che-gar a muitas mais pessoas e, por outro, de reduzir significativamente orisco de se perder o conhecimento por problemas de transmissão. De facto,a palavra escrita permite preservar por muito tempo e sem qualquer tipode adulteração o conhecimento que o autor pretendeu transmitir.

É graças à palavra escrita que hoje conseguimos compreender e acumu-lar um vastíssimo conjunto de conhecimentos, muitos deles registados hámilhares de anos atrás.

Infelizmente, nem sempre a palavra escrita conseguiu transmitir comrigor aquilo que o autor pretendia. A língua natural tem inúmeras ambi-guidades e evolui substancialmente com o tempo, o que leva a que a inter-pretação dos textos seja sempre uma tarefa subjectiva. Quer quando escre-vemos um texto, quer quando o lemos e o interpretamos, existem omissões,imprecisões, incorrecções e ambiguidades que podem tornar a transmissãode conhecimento falível. Se o conhecimento que se está a transmitir forsimples, o receptor da informação, em geral, consegue ter a cultura e ima-ginação suficientes para conseguir ultrapassar os obstáculos mas, no casoda transmissão de conhecimentos mais complexos já isso poderá ser muitomais difícil.

Infelizmente, quando se exige rigor na transmissão de conhecimento,fazer depender a compreensão desse conhecimento da capacidade de inter-pretação de quem o recebe pode ter consequências desastrosas e, de facto,a história da humanidade está repleta de acontecimentos catastróficos cujacausa é, tão somente, uma insuficiente ou errónea transmissão de conheci-mento.

Para evitar estes problemas, inventaram-se linguagens mais rigorosas.A matemática, em particular, tem-se obssessivamente preocupado ao longodos últimos milénios com a construção de uma linguagem onde o rigor seja

4

Page 6: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

absoluto. Isto permite que a transmissão do conhecimento matemático sejamuito mais rigorosa que nas outras áreas, reduzindo ao mínimo essencial acapacidade de imaginação necessária de quem está a absorver esse conhe-cimento.

Para melhor percebermos do que estamos a falar, consideremos um casoconcreto de transmissão de conhecimento, por exemplo, o cálculo do facto-rial de um número. Se assumirmos, como ponto de partida, que a pessoa aquem queremos transmitir esse conhecimento já sabe de antemão o que sãoos números e as operações aritméticas, podemos dizer-lhe que para calcularo factorial de um número qualquer, terá de multiplicar todos os números desde aunidade até esse número. Infelizmente, esta descrição é demasiado extensae, pior, é pouco rigorosa, pois não dá ao ouvinte a informação de que osnúmeros que ele tem de multiplicar são apenas os números inteiros. Paraevitar estas imprecisões e, simultaneamente, tornar mais compacta a infor-mação a transmitir, a Matemática inventou todo um conjunto de símbolose conceitos cujo significado deve ser compreendido por todos. Por exem-plo, para indicar a sequência de números inteiros entre 1 e 9, a Matemáticapermite-nos escrever 1, 2, 3, . . . , 9. Do mesmo modo, para evitarmos falarde “um número qualquer,” a Matemática inventou o conceito de variável: umnome que designa qualquer “coisa” e que pode ser reutilizado em váriaspartes de uma afirmação matemática com o significado óbvio de repre-sentar sempre essa mesma “coisa.” Deste modo, a linguagem Matemáticapermite-nos formular a mesma afirmação sobre o cálculo do factorial nosseguintes termos:

n! = 1× 2× 3× · · · × n

Será a definição anterior suficientemente rigorosa? Será possível interpretá-la sem necessitar de imaginar a intenção do autor? Aparentemente, simmas, na verdade, há um detalhe da definição que exige imaginação: as re-ticências. Aquelas reticências indicam ao leitor que ele terá de imaginar oque deveria estar no lugar delas e, embora a maioria dos leitores irá ima-ginar correctamente que o autor pretendia a multiplicação dos sucessoresdos números anteriores, leitores haverá cuja imaginação delirante poderátentar substituir aquelas reticências por outra coisa qualquer.

Mesmo que excluamos do nosso público-alvo as pessoas de imaginaçãodelirante, há ainda outros problemas com a definição anterior. Pensemos,por exemplo, no factorial de 2. Qual será o seu valor? Se substituirmos nafórmula, para n = 2 obtemos:

2! = 1× 2× 3× · · · × 2

5

Page 7: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Neste caso, não só as reticências deixam de fazer sentido como toda a fór-mula deixa de fazer sentido, o que mostra que, na verdade, a imaginaçãonecessária para a interpretação da fórmula original não se restringia apenasàs reticências mas sim a toda a fórmula: o número de termos a considerardepende do número do qual queremos saber o factorial.

Admitindo que o nosso leitor teria tido a imaginação suficiente paradescobrir esse detalhe, ele conseguiria tranquilamente calcular que 2! =1 × 2 = 2. Ainda assim, casos haverá que o deixarão significativamentemenos tranquilo. Por exemplo, qual é o factorial de zero? A resposta nãoparece óbvia. E quanto ao factorial de −1? Novamente, não está claro. Equanto ao factorial de 4.5? Mais uma vez, a fórmula nada diz e a nossaimaginação também não consegue adivinhar.

Será possível encontrar uma forma de transmitir o conhecimento dafunção factorial que minimize as imprecisões, lacunas e ambiguidades?Será possível reduzir ao mínimo razoável a imaginação necessária paracompreender esse conhecimento? Experimentemos a seguinte variante dadefinição da função factorial:

n! =

{1, se n = 0n · (n− 1)!, se n ∈ N.

Teremos agora atingido o rigor suficiente que dispensa imaginação porparte do leitor? A resposta estará na análise dos casos que causaram pro-blemas à definição anterior. Em primeiro lugar, não existem reticências, oque é positivo. Em segundo lugar, para o factorial de 2 temos, pela defini-ção:

2! = 2× 1! = 2× (1× 0!) = 2× (1× 1) = 2× 1 = 2

ou seja, não há qualquer ambiguidade. Finalmente, vemos que não fazsentido determinar o factorial de −1 ou de 4.5 pois a definição apresentadaapenas se aplica aos membros de N0.

Este exemplo mostra que, mesmo na matemática, há diferentes grausde rigor nas diferentes formas como se expõe o conhecimento. Algumasdessas formas exigem um pouco mais de imaginação e outras um poucomenos mas, em geral, qualquer delas tem sido suficiente para que a huma-nidade tenha conseguido preservar o conhecimento adquirido ao longo dasua história.

Acontece que, actualmente, a humanidade conta com um parceiro quetem dado uma contribuição gigantesca para o seu progresso: o computa-dor. Esta máquina tem a extraordinária capacidade de poder ser instruídade forma a saber executar um conjunto complexo de tarefas. A actividade

6

Page 8: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

da programação consiste, precisamente, da transmissão, a um computador,do conhecimento necessário para resolver um determinado problema. Esseconhecimento é denominado um programa. Por serem programáveis, os com-putadores têm sido usados para os mais variados fins e, sobretudo nas úl-timas décadas, têm transformado radicalmente a forma como trabalhamos.Infelizmente, a extraordinária capacidade de “aprendizagem” dos compu-tadores vem acompanhada duma igualmente extraordinária incapacidadede imaginação. O computador não imagina, apenas interpreta rigorosa-mente o conhecimento que lhe transmitimos sob a forma de um programa.

Uma vez que não tem imaginação, o computador depende criticamentedo modo como lhe apresentamos o conhecimento que queremos transmi-tir: esse conhecimento tem de estar descrito numa linguagem tal que nãopossa haver margem para qualquer ambiguidade, lacuna ou imprecisão.Uma linguagem com estas características denomina-se, genericamente, delinguagem de programação.

1.1 Linguagens de Programação

Para que um computador possa resolver um problema é necessário queconsigamos fazer uma descrição do processo de resolução desse problemanuma linguagem que o computador entenda. Infelizmente, a linguagemque os computadores entendem de forma “inata” é extraordinariamentepobre, levando a que a qualquer problema não trivial acabe por exigir umaexaustiva, entediante e extremamente complexa descrição do processo deresolução. As inúmeras linguagens de programação que têm sido inventa-das visam precisamente aliviar o programador desse fardo, introduzindoelementos linguísticos capazes de simplificar enormemente essas descri-ções. Por exemplo, os conceitos de função, matriz, somatório, ou número raci-onal não existem nativamente nos computadores mas muitas linguagens deprogramação permitem a sua utilização de modo a facilitar a descrição decálculos científicos. Isto implica, naturalmente, que tem de existir um pro-cesso capaz de transformar as descrições que o programador faz em descri-ções que o computador entenda. Embora este processo seja relativamentecomplexo, o que nos importa saber é que ele permite termos linguagens deprogramação mais próximas das capacidades do pensamento humano doque das capacidades de pensamento do computador.

Este último facto tem uma importância crucial pois permite que passe-mos a usar linguagens de programação, não só para instruir um compu-tador sobre uma forma de resolver um problema, mas também para expli-car rigorosamente esse processo a outros seres humanos. A linguagem de

7

Page 9: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

programação torna-se assim um meio de transmissão de conhecimento, talcomo a linguagem da matemática o foi nos últimos milhares de anos.

Existe uma enorme diversidade de linguagens de programação, umasmais apetrechadas para a resolução de um determinado tipo de problemas,outras mais apetrechadas para a resolução de outro tipo de problemas. Aescolha de uma linguagem de programação deve estar condicionada, natu-ralmente, pelo tipo de problemas que queremos resolver, mas não deve serum comprometimento total. Para quem programa é muito mais importantecompreender os fundamentos e técnicas da programação do que dominaresta ou aquela linguagem. No entanto, para mais rigorosamente se explicaraqueles fundamentos e técnicas, convém exemplificá-los numa linguagemde programação concreta.

Uma vez que este texto se irá focar na programação aplicada à Arquitec-tura, vamos empregar uma linguagem de programação que esteja particu-larmente vocacionada para resolver problems geométricos. Várias lingua-gens existem com esta vocação, em geral associadas a ferramentas de de-senho assistido por computador. O ArchiCAD, por exemplo, disponibilizauma linguagem de programação denominada GDL— acrónimo de Geome-tric Description Language—que permite ao utilizador programar as váriasformas geométricas pretendidas. Já no caso do AutoCad, a linguagem deprogramação empregue é o Auto Lisp, um dialecto de uma famosa lingua-gem de programação denominada Lisp.

Embora a linguagem GDL aparente ser muito diferente da linguagemAuto Lisp, os conceitos fundamentais são muito semelhantes. É sobre estesconceitos fundamentais da programação que nos iremos debruçar embora,por motivos pedagógicos, seja conveniente particularizá-los numa únicalinguagem. Neste texto iremos explicar os fundamentos da programaçãoatravés da utilização da linguagem Auto Lisp, não só pela sua facilidadede aprendizagem mas também pela sua aplicabilidade prática. No entanto,uma vez apreendidos esses fundamentos, o leitor deverá ser capaz de ostraduzir para qualquer outra linguagem de programação.

1.2 Lisp

Lisp é uma linguagem de programação extremamente simples mas comenorme flexibilidade. Embora tenha sido inicialmente inventada como umalinguagem matemática, cedo se procedeu à sua implementação em diver-sos computadores, o que os tornou em executores dos processos descritosnos programas Lisp.

Desde a sua génese que a linguagem Lisp prima pela enorme facilidade

8

Page 10: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

de extensão. Isto permite ao programador ampliar a linguagem, dotando-ade novos meios para resolver problemas. Esta capacidade permitiu ao Lispsobreviver à evolução da informática. Embora outras linguagens se tenhamtornado obsoletas, a linguagem Lisp continua activa e é a segunda maisantiga linguagem ainda em utilização, sendo apenas ultrapassada pela lin-guagem Fortran.

A facilidade de utilização, adaptação e extensão da linguagem fez comque surgissem dezenas de diferentes dialectos: FranzLisp, ZetaLisp, Le-Lisp, MacLisp, InterLisp, Scheme, T, Nil, XLisp e AutoLISP são apenas al-guns dos exemplos mais relevantes. Neste livro iremos debruçarmo-nossobre o dialecto AutoLISP.

A linguagem AutoLISP derivou da linguagem XLisp e foi incorporadano AutoCad em 1986, tendo sido intensivamente usada desde então. Em1999, o AutoCad passou a disponibilizar uma versão melhorada do Au-toLisp denominada Visual LISP que, entre outras diferenças, possui umcompilador para uma execução mais eficiente e um depurador de progra-mas para facilitar a detecção e correcção de erros. A influência do AutoCadé tão grande que vários outros vendedores decidiram incluir uma imple-mentação de AutoLISP nos seus próprios produtos, de modo a facilitar atransição de utilizadores.

Um aspecto característico do Lisp é ser uma linguagem interactiva. Cadaporção de um programa pode ser desenvolvida, testada e corrigida inde-pendentemente das restantes. Deste modo, Lisp permite que o desenvolvi-mento, teste e correcção de programas seja feito de uma forma incremental,o que facilita muito a tarefa do programador.

Embora os exemplos que iremos apresentar sejam válidos apenas emAutoLISP, falaremos genericamente da linguagem Lisp e, apenas quandonecessário, mencionaremos o AutoLISP.

1.3 Exercícios

Exercício 1.3.1 A exponenciação bn é uma operação entre dois números b e n designadosbase e expoente, respectivamente. Quando n é um inteiro positivo, a exponenciação define-se como uma multiplicação repetida:

bn = b× b× · · · × b| {z }n

Para um leitor que nunca tenha utilizado o operador de exponenciação, a definiçãoanterior levanta várias questões cujas respostas poderão não lhe ser evidentes. Quantasmultiplicações são realmente feitas? Serão n multiplicações? Serão n− 1 multiplicações? Oque fazer no caso b1? E no caso b0?

Proponha uma definição matemática de exponenciação que não levante estas questões.

9

Page 11: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Exercício 1.3.2 O que é uma linguagem de programação? Para que serve?

2 Sintaxe, Semântica e Pragmática

Todas as linguagens possuem sintaxe, semântica e pragmática.Em termos muito simples, podemos descrever a sintaxe de uma lingua-

gem como o conjunto de regras que determinam as frases que se podemconstruir nessa linguagem. Sem sintaxe, qualquer concatenação arbitráriade palavras constituiria uma frase. Por exemplo, dadas as palavras “João,”“o,” “comeu,” e “bolo,” as regras da sintaxe da língua Portuguesa dizem-nos que “o João comeu o bolo” é uma frase e que “o comeu João bolo bolo”não é uma frase. Note-se que, de acordo com a sintaxe do Português, “obolo comeu o João” é também uma frase sintaticamente correcta.

A sintaxe regula a construção das frases mas nada diz acerca do seusignificado. É a semântica de uma linguagem que nos permite atribuir sig-nificado às frases da linguagem e que nos permite perceber que a frase “obolo comeu o João” não faz sentido.

Finalmente, a pragmática diz respeito à forma usual como se escrevemas frases da linguagem. Para uma mesma linguagem, a pragmática variade contexto para contexto: a forma como dois amigos íntimos falam entresi é diferente da forma usada por duas pessoas que mal se conhecem.

Estes três aspectos das linguagens estão também presentes quando dis-cutimos linguagens de programação. Contrariamente ao que acontece comas linguagens naturais que empregamos para comunicarmos uns com osoutros, as linguagens de programação caracterizam-se por serem formais,obedecendo a um conjunto de regras muito mais simples e rígido que per-mite que sejam analisadas e processadas mecanicamente.

Neste texto iremos descrever a sintaxe e semântica da linguagem AutoLisp. Embora existam formalismos matemáticos que permitem descreverrigorosamente aqueles dois aspectos das linguagens, eles exigem uma so-fisticação matemática que, neste trabalho, é desapropriada. Por este mo-tivo, iremos apenas empregar descrições informais.

Quanto à pragmática, esta será explicada à medida que formos intro-duzindo os elementos da linguagem. A linguagem Auto Lisp promoveuma pragmática que, nalguns aspectos, difere significativamente do que éhabitual nos restantes dialectos de Lisp. Uma vez que a pragmática não in-fluencia a correcção dos nossos programas mas apenas o seu estilo, iremosempregar uma pragmática ligeiramente diferente da usual em Auto Lispmas que pensamos ser mais apropriada.

10

Page 12: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

2.1 Sintaxe e Semântica do Lisp

Quando comparada com a grande maioria das outras linguagens de pro-gramação, a linguagem Lisp possui uma sintaxe extraordinariamente sim-ples baseada no conceito de expressão.1

Uma expressão, em Lisp, pode ser construída empregando elementosprimitivos como, por exemplo, os números; ou combinando outras expres-sões entre si como, por exemplo, quando somamos dois números. Comoiremos ver, esta simples definição permite-nos construir expressões de com-plexidade arbitrária. No entanto, convém relembrarmos que a sintaxe res-tringe aquilo que podemos escrever: o facto de podermos combinar ex-pressões para produzir outras expressões mais complexas não nos autorizaa escrever qualquer combinação de subexpressões. As combinações obede-cem a regras sintáticas que iremos descrever ao longo do texto.

À semelhança do que acontece com a sintaxe, também a semântica dalinguagem Lisp é, em geral, substancialmente mais simples que a de outraslinguagens de programação. Como iremos ver, a semântica é determinadapelos operadores que as nossas expressões irão empregar. Um operador desoma, por exemplo, serve para somar dois números. Uma combinação quejunte este operador e, por exemplo, os números 3 e 4 tem, como signifi-cado, a soma de 3 com 4, i.e., 7. No caso das linguagens de programação, asemântica de uma expressão é dada pelo computador que a vai avaliar.

2.2 O Avaliador

Em Lisp, qualquer expressão tem um valor. Este conceito é de tal modoimportante que todas as implementações da linguagem Lisp apresentamum avaliador, i.e., um programa destinado a interagir com o utilizador demodo a avaliar expressões por este fornecidas.

No caso do AutoCad, o avaliador está contido num ambiente interac-tivo de desenvolvimento, denominado Visual Lisp e pode ser acedido atra-vés de menus (menu “Tools”, submenu “AutoLISP”, item “Visual LISP Edi-tor”) ou através do comando vlisp. Uma vez acedido o Visual Lisp, outilizador encontrará uma janela com o título “Visual LISP Console” e quese destina precisamente à interacção com o avaliador de Auto Lisp.

Assim, quando o utilizador começa a trabalhar com o Lisp, é-lhe apre-sentado um sinal (denominado “prompt”) e o Lisp fica à espera que o utili-zador lhe forneça uma expressão.

1Originalmente, Lisp dizia-se baseado em S-expression, uma abreviatura para expressõessimbólicas. Esta caracterização ainda é aplicável mas, por agora, não a vamos empregar.

11

Page 13: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

_$

O texto “_$” é a “prompt” do Lisp, à frente da qual vão aparecer asexpressões que o utilizador escrever. O Lisp interacciona com o utilizadorexecutando um ciclo em que lê uma expressão, determina o seu valor eescreve o resultado. Este ciclo de acções designa-se, tradicionalmente, deread-eval-print-loop (e abrevia-se para REPL).

Quando o Lisp lê uma expressão, constroi internamente um objecto quea representa. Esse é o papel da fase de leitura. Na fase de avaliação, oobjecto construído é analisado de modo a produzir um valor. Esta análiseé feita empregando as regras da linguagem que determinam, para cadacaso, qual o valor do objecto construído. Finalmente, o valor produzido éapresentado ao utilizador na fase de escrita através de uma representaçãotextual desse valor.

Dada a existência do read-eval-print-loop, em Lisp não é necessário ins-truir o computador a escrever explicitamente os resultados de um cálculocomo acontece noutras linguages como, por exemplo, em Java. Isto per-mite que o teste e correcção de erros seja bastante facilitada. A vantagem deLisp ser uma linguagem interactiva está na rapidez com que se desenvol-vem protótipos de programas, escrevendo, testando e corrigindo pequenosfragmentos de cada vez.

Exercício 2.2.1 O que é o REPL?

3 Elementos da Linguagem

Em qualquer linguagem de programação precisamos de lidar com duasespécies de objectos: dados e procedimentos. Os dados são as entidadesque pretendemos manipular. Os procedimentos são descrições das regraspara manipular esses dados.

Se considerarmos a linguagem da matemática, podemos identificar osnúmeros como dados e as operações algébricas como procedimentos. Asoperações algébricas permitem-nos combinar os números entre si. Por exem-plo, 2 × 2 é uma combinação. Uma outra combinação envolvendo maisdados será 2 × 2 × 2 e, usando ainda mais dados, 2 × 2 × 2 × 2. No en-tanto, a menos que pretendamos ficar eternamente a resolver problemas dearitmética elementar, convém considerar operações mais elaboradas querepresentam padrões de cálculos. Na sequência de combinações que apre-sentámos é evidente que o padrão que está a emergir é o da operação depotenciação, i.e, multiplicação sucessiva, tendo esta operação sido definida

12

Page 14: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

na matemática há já muito tempo. A potenciação é, portanto, uma abstrac-ção de uma sucessão de multiplicações.

Tal como a linguagem da matemática, uma linguagem de programaçãodeve possuir dados e procedimentos primitivos, deve ser capaz de combi-nar quer os dados quer os procedimentos para produzir dados e procedi-mentos mais complexos e deve ser capaz de abstrair padrões de cálculo demodo a permitir tratá-los como operações simples, definindo novas opera-ções que representem esses padrões de cálculo.

Mais à frente iremos ver como é possível definir essas abstracções emLisp mas, por agora, vamos debruçar-nos sobre os elementos mais básicos,os chamados elementos primitivos da linguagem.

3.1 Elementos primitivos

Elementos primitivos são as entidades mais simples com que a linguagemlida. Os elementos primitivos podem ser divididos em dados primitivose procedimentos primitivos. Um número, por exemplo, é um dado primi-tivo. Já a operação de adição de números é um procedimento primitivo.

3.1.1 Números

Como dissemos anteriormente, o Lisp executa um ciclo read-eval-print. Istoimplica que tudo o que escrevemos no Lisp tem de ser avaliado, i.e., temde ter um valor, valor esse que o Lisp escreve no écran.

Assim, se dermos um número ao avaliador, ele devolve-nos o valordesse número. Quanto vale um número? O melhor que podemos dizeré que ele vale por ele próprio. Por exemplo, o número 1 vale 1.

_$ 11_$ 1234512345_$ 4.54.5

Como se vê no exemplo, em Lisp, os números podem ser inteiros oureais. Os reais são números com um ponto decimal e, no caso do Auto Lisp,tem de haver pelo menos um dígito antes do ponto decimal:

_$ 0.10.1_$ .1; error: misplaced dot on input

13

Page 15: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Note-se, no exemplo anterior, que o Auto Lisp produziu um erro. Umerro é uma situação anómala que impede o Auto Lisp de prosseguir o queestava a fazer. Neste caso, é apresentada uma mensagem de erro e o AutoLisp volta ao princípio do ciclo read-eval-print.

Exercício 3.1.1 Descubra qual é o maior real e o maior inteiro que o seu Lisp aceita.

Os reais podem ser escritos em notação decimal ou científica consoanteo seu tamanho.

3.1.2 Cadeias de Caracteres

As cadeias de caracteres (também denominadas strings) são outro tipo de da-dos primitivo. Um carácter é uma letra, um dígito ou qualquer outro sím-bolo gráfico, incluindo os símbolos gráficos não visíveis como o espaço, atabulação e outros. Uma cadeia de caracteres é especificada através de umasequência de caracteres delimitada por aspas. Tal como com os números, ovalor de uma cadeia de caracteres é a própria cadeia de caracteres.

_$ "Ola""Ola"_$ "Eu sou o meu valor""Eu sou o meu valor"

Sendo uma string delimitada por aspas fica a dúvida sobre como criaruma string que contém aspas. Para isso, e para outros caracteres especiais,existe um carácter que o Auto Lisp interpreta de forma distinta: quando,na criação de uma string, aparece o carácter \ ele assinala que o próximocarácter tem de ser processado de forma especial. Por exemplo, para se acriar a string correspondente à frase

O Manuel disse “Bom dia!” ao Pedro.

temos de escrever:

"O Manuel disse \"Bom dia!\" ao Pedro."

O carácter \ é denominado um carácter de escape e permite a inclusãoem strings de caracteres que, de outra forma, seriam difíceis de inserir. ATabela 1 mostra as várias possibilidades.

Para além dos números e das strings, o Auto Lisp possui ainda outrostipos de elementos primitivos que iremos explicar mais tarde.

14

Page 16: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Sequência Resultado\\ o carácter \ (backslash)\" o carácter " (aspas)\e o carácter escape\n o carácter de mudança de linha (newline)\r o carácter de mudança de linha (carriage return)\t o carácter de tabulação (tab)\nnn o carácter cujo código octal é nnn

Tabela 1: Caracteres de escape válidos em Auto Lisp

3.2 Combinações

Uma combinação é uma expressão que descreve a aplicação de um opera-dor aos seus operandos. Por exemplo, na matemática, os números podemser combinados usando operações como a soma ou o produto. Como exem-plo de combinações matemáticas, temos 1+2 e 1+2×3. A soma e o produtode números são exemplos de operações extremamente elementares consi-deradas procedimentos primitivos.

Em Lisp, cria-se uma combinação escrevendo uma sequência de expres-sões entre um par de parênteses. Uma expressão é um elemento primitivoou uma outra combinação. A expressão (+ 1 2) é uma combinação doselementos primitivos 1 e 2 através do procedimento primitivo +. Já nocaso (+ 1 (* 2 3)) a combinação é entre 1 e (* 2 3), sendo esta últimaexpressão uma outra combinação. Note-se que cada expressão deve serseparada das restantes por um ou mais espaços. Assim, embora a combi-nação (* 2 3) possua as três expressões *, 2 e 3, a combinação (*2 3) sópossui duas—*2 e 3—sendo que a primeira delas não tem qualquer signi-ficado pré-definido.

Por agora, as únicas combinações com utilidade são aquelas em que asexpressões correspondem a operadores e operandos. Por convenção, o Lispconsidera que o primeiro elemento de uma combinação é um operador e osrestantes são os operandos.

A notação que o Lisp utiliza para construir expressões (operador pri-meiro e operandos a seguir) é designada por notação prefixa por o opera-dor ocorrer préviamente aos operandos. Esta notação costuma causar al-guma perplexidade a quem inicia o estudo da linguagem, que espera umanotação mais próxima da que aprendeu em aritmética e que é usada ha-bitualmente nas outras linguagens de programação. Nestas, a expressão(+ 1 (* 2 3)) é usualmente escrita na forma 1 + 2 * 3 (designada no-

15

Page 17: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

tação infixa, por o operador ocorrer entre os operandos) que, normalmente,é mais simples de ler por um ser humano. No entanto, a notação prefixausada pelo Lisp tem vantagens sobre a notação infixa:

• É muito fácil usar operadores que têm um número variável de ope-randos,2 como por exemplo (+ 1 2 3) ou (+ 1 2 3 4 5 6 7 8 9 10).Na maioria das outras linguagens de programação apenas existemoperadores unários ou binários e é necessário explicitar os opera-dor binários entre cada dois operandos: 1 + 2 + 3 ou 1 + 2 + 3+ 4 + 5 + 6 + 7 + 8 + 9 + 10. Se se pretender um operadorternário (ou outro) já não se consegue escrever do mesmo modo.

• Não existe precedência entre os operadores. Nas linguagens de no-tação infixa, a expressão 1 + 2 * 3 tem de ser calculada como sese tivesse escrito 1 + (2 * 3), e não (1 + 2) * 3, i.e., foi cri-ada uma precedência para eliminar as ambiguidades. Essa precedên-cia pode ser alterada através do emprego de parênteses. Em Lisp,as expressões seriam necessariamente distintas, (+ 1 (* 2 3)) ou(* (+ 1 2) 3), não podendo haver qualquer ambiguidade.

• Os operadores que nós definimos usam-se exactamente da mesmamaneira que os operadores da linguagem: operador primeiro e ope-randos a seguir. Na maioria das outras linguagens, os operadoressão infixos, i.e., estão entre os operandos, e os procedimentos por nósdefinidos são prefixos, i.e., primeiro vem o nome do procedimento edepois os operandos. Isto impede a extensão da linguagem de umaforma coerente.

Para exemplificar este último aspecto, consideremos a operação deexponenciação numa linguagem com operadores infixos. Para ser co-erente com o resto da linguagem, deveria existir um operador, porexemplo ** que permitisse escrever 3**4 para indicar a quarta po-tência de 3. Como, em geral, esse operador não existe, somos obri-gados a criar um procedimento que o implemente mas, neste caso,a sintaxe muda radicalmente pois, em geral, o utilizador não podedefinir novos operadores infixos. A consequência é que o novo ope-rador, por não se poder usar de forma infixa e ter de se usar de formaprefixa, não fica coerente com as restantes operações da linguagem,como a soma e a multiplicação. Em Lisp, pelo contrário, tanto po-

2Estes operadores dizem-se variádicos.

16

Page 18: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

demos escrever (* 3 3 3 3) como definir uma função que permitaescrever (** 3 4).

Para além das notações infixa e prefixa existe ainda a notação posfixaem que o operador se escreve após os operandos. Esta notação tem as mes-mas propriedades da notação prefixa mas é, em geral, mais difícil de lerpelo facto de ser necessário ler todos os operandos antes de se perceber oque se vai fazer com eles.

3.3 Indentação

A desvantagem da notação prefixa está na escrita de combinações comple-xas. Por exemplo, a expressão 1+2*3-4/5*6 lê-se com relativa facilidademas, quando escrita na sintaxe do Lisp,(- (+ 1 (* 2 3)) (* (/ 4 5) 6)),fica com uma forma que, para quem não está ainda habituado, pode sermais difícil de perceber devido à acumulação de parênteses.

Para tornarmos estas expressões mais fáceis de entender, podemos (edevemos) empregar a técnica da indentação. Esta técnica baseia-se no usode diferentes alinhamentos na disposição textual dos programas de modo afacilitar a sua leitura. Assim, ao invés de escrevermos as nossas expressõestodas numa linha ou com arranjos arbitrários entre linhas, escrevemo-lasao longo de várias linhas e com um alinhamento entre linhas que mostre orelacionamento das várias subexpressões com a expressão que as contém.

A regra para indentação de combinações Lisp é extremamente simples:numa linha coloca-se o operador e o primeiro operando; os restantes ope-randos vêm alinhados por debaixo do primeiro, usando-se um número su-ficiente de espaços em branco à esquerda para que os operandos fiquemcorrectamente arrumados. No caso de uma expressão ser curta, podemosescrevê-la numa só linha, com os operandos logo a seguir ao operador, comum espaço em branco entre cada um. Usando estas duas regras, podemosreescrever a expressão anterior na seguinte forma, onde usamos linhas ver-ticais imaginárias para salientar a indentação:

(- (+ 1(* 2 3))

(* (/ 4 5)6))

Note-se que o facto de se dispor uma combinação ao longo de váriaslinhas em nada afecta a forma como o Lisp a lê pois a correcta delimitaçãodos elementos da combinação é feita apenas pela sua separação visual epela utilização de parênteses correctamente emparelhados.

17

Page 19: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Quando a regra de indentação não é suficiente para produzir uma dis-posição de linhas de texto que seja esteticamente agradável, usam-se pe-quenas variações, como seja colocar o operador numa linha e os operandospor debaixo, por exemplo:

(um-operador-com-um-nome-muito-grande1 2 3 4)

No caso geral, podemos ter de empregar as várias regras em simultâ-neo:

(um-operador (um-operador-com-um-nome-muito-grande1 2 3 4)

(outro-operador 56(e-ainda-outro 7

8))(e-o-ultimo-operador 9 10))

Alguns operadores da linguagem possuem uma regra de indentaçãoprópria. Essas regras serão explicadas à medida que formos introduzindoesses operadores.

A indentação é fundamental em Lisp pois é muito fácil escrever códigocomplexo. A grande maioria dos editores preparados para Lisp formatamautomaticamente os programas à medida que os escrevemos e mostram oemparelhamento de parênteses. Desta forma, após algum tempo de prá-tica, torna-se muito fácil escrever e ler os programas, por mais complexaque possa parecer a sua estrutura.

Exercício 3.3.1 Qual é a diferença entre a notação prefixa e a notação infixa?

Exercício 3.3.2 Em matemática, é usal empregar simultaneamente as diferentes notaçõesprefixa, infixa e posfixa. Escreva exemplos de expressões matemáticas que utilizem estasdiferentes notações.

Exercício 3.3.3 Converta as seguintes expressões da notação infixa da aritmética para anotação prefixa 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

18

Page 20: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

7. 1− (2 + 3)

8. 2× 2 + 3× 3× 3

Exercício 3.3.4 Converta as seguintes expressões da notação prefixa do Lisp para a notaçãoinfixa da aritmética:

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)

Exercício 3.3.5 Indente a seguinte expressão de modo a ter um único operando por linha.(* (+ (/ 3 2) (- (* (/ 5 2) 3) 1) (- 3 2)) 2)

3.4 Avaliação de Combinações

Como já vimos, o Lisp considera que o primeiro elemento de uma combi-nação é um operador e os restantes são os operandos.

O avaliador determina o valor de uma combinação como o resultado deaplicar o procedimento especificado pelo operador ao valor dos operandos.O valor de cada operando é designado de argumento do procedimento.Assim, o valor da combinação (+ 1 (* 2 3)) é o resultado de somar ovalor de 1 com o valor de (* 2 3). Como já se viu, 1 vale 1 e (* 2 3) éuma combinação cujo valor é o resultado de multiplicar o valor de 2 pelovalor de 3, o que dá 6. Finalmente, somando 1 a 6 obtemos 7.

_$ (* 2 3)6_$ (+ 1 (* 2 3))7

Uma diferença importante entre o Auto Lisp e a aritmética ocorre naoperação de divisão. Matematicamente falando, 7/2 é uma fracção, i.e.,não é um número inteiro. Infelizmente, o Auto Lisp não sabe lidar comfracções e, consequentemente, emprega uma definição ligeiramente dife-rente para o operador de divisão: em Auto Lisp, o símbolo / representaa divisão inteira, i.e., o número que multiplicado pelo divisor e somado aoresto iguala o dividendo. Assim, (/ 7 2) avalia para 3. No entanto, quandoestá a lidar com números reais, o Auto Lisp já faz a divisão segundo asregras da matemática mas, possivelmente, envolvendo perdas de precisão.Assim, (/ 7.0 2) produz 3.5.

19

Page 21: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Exercício 3.4.1 Calcule o valor das seguintes expressões Lisp:

1. (* (/ 1 2) 3)

2. (* 1 (- 2 3))

3. (/ (+ 1 2) 3)

4. (- (- 1 2) 3)

5. (- 1 2 3)

6. (- 1)

3.5 Operadores de Strings

Para além dos operadores que já vimos para números, existem operadorespara strings. Por exemplo, para concatenar várias strings, existe o operadorstrcat. A concatenação de várias strings produz uma só string com todosos caracteres dessas várias 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 número de caracteres de uma string existe o operador strlen:

_$ (strlen (strcat "eu" " " "sou" " " "uma" " " "string"))17_$ (strlen "")0

Note-se que as aspas são os delimitadores de strings e não contam comocaracteres.

A função substr providencia uma terceira operação útil com strings:ela permite obter parte de uma string. A parte a obter é especificada atravésda posição do primeiro carácter e do número de caracteres a considerar.Numa string, a posição de um carácter é também denominada de índicedo caracter. O Auto Lisp considera que o primeiro carácter de uma stringtem o índice 1. A função substr recebe, como argumentos, uma string,um índice e, opcionalmente, um número de caracteres e devolve a parteda string que começa no índice dado e que tem o número de caracteresdado no parâmetro opcional ou todos os restantes caracteres no caso deesse número não ter sido dado. Assim, temos:

20

Page 22: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

_$ (substr "abcd" 1)"abcd"_$ (substr "abcd" 2)"bcd"_$ (substr "abcd" 2 2)"bc"

Exercício 3.5.1 Qual é o resultado das seguintes avaliações?

1. (strcat "a" "vista" "da" " baixa" "da" " banheira")

2. (substr (strcat "Bom dia") 1 3)

3. (substr (strcat "Bom dia") 5)

3.6 Definição de Funções

Para além das operações básicas aritméticas, a matemática disponibiliza-nos um vastíssimo conjunto de outras operações que se definem à custadaquelas. Por exemplo, o quadrado de um número é uma operação (tambémdesignada por função) que, dado um número, produz o resultado de multi-plicar esse número por ele próprio. Matematicamente falando, define-se oquadrado de um número pela função x2 = x · x.

Tal como em matemática, pode-se definir numa linguagem de progra-mação a função que obtém o quadrado de um número. Em Lisp, paraobtermos o quadrado de um número qualquer, por exemplo, 5, escreve-mos a combinação (* 5 5). No caso geral, dado um número qualquer x,sabemos que obtemos o seu quadrado escrevendo (* x x). Falta apenasassociar um nome que indique que, dado um número x, obtemos o seu qua-drado avaliando (* x x). Lisp permite-nos fazer isso através da operaçãodefun (abreviatura de define function):

_$ (defun quadrado (x) (* x x))QUADRADO

Note-se que o Auto Lisp, ao avaliar a definição da função quadradodevolve como valor o nome da função definida. Note-se ainda que o AutoLisp escreve esse nome em maiúsculas. Na realidade, o que se passa é que,por motivos históricos, todos os nomes que escrevemos no Auto Lisp sãotraduzidos para maiúsculas assim que são lidos. Por este motivo, quadrado,QUADRADO, Quadrado, qUaDrAdo, ou qualquer outra combinação de maiús-culas e minúsculas designa o mesmo nome em Auto Lisp: QUADRADO. Ape-sar da conversão para maiúsculas que é feita na leitura, é pragmática usualescrevermos os nossos programas em letras minúsculas.

21

Page 23: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Como se pode ver pela definição da função quadrado, para se defi-nirem novos procedimentos em Lisp, é necessário criar uma combinaçãode quatro elementos. O primeiro elemento desta combinação é a palavradefun, que informa o avaliador que estamos a definir uma função. O se-gundo elemento é o nome da função que queremos definir, o terceiro ele-mento é uma combinação com os parâmetros da função e o quarto elementoé a expressão que determina o valor da função para aqueles parâmetros. Demodo genérico podemos indicar que a definição de funções é feita usandoa seguinte forma:

(defun nome (parâmetro1 ... parâmetron)corpo)

Quando se dá uma expressão desta forma ao avaliador, ele acrescentaa função ao conjunto de funções da linguagem, associando-a ao nome quelhe demos e devolve como valor da definição o nome da função definida.Se já existir uma função com o mesmo nome, a definição anterior é sim-plesmente esquecida. Os parâmetros de um procedimento são designadosparâmetros formais e são os nomes usados no corpo de expressões para nosreferirmos aos argumentos correspondentes. Quando escrevemos no avali-ador de Lisp (quadrado 5), 5 é o argumento do procedimento. Durante ocálculo da função este argumento está associado ao parâmetro formal x. Osargumentos de uma função são também designados por parâmetros actuais.

No caso da função quadrado, a sua definição diz que para se determi-nar o quadrado de um número x, devemos multiplicar esse número por elepróprio (* x x). Esta definição associa a palavra quadrado a um procedi-mento, i.e., a uma descrição do modo de produzir o resultado pretendido.Note-se que este procedimento possui parâmetros, permitindo o seu usocom diferentes argumentos. Para se utilizar este procedimento, podemosavaliar as seguinte expressões:

_$ (quadrado 5)25_$ (quadrado 6)36

A regra de avaliação de combinações que descrevemos anteriormente étambém válida para as funções por nós definidas. Assim, a avaliação da ex-pressão (quadrado (+ 1 2)) passa pela avaliação do operando (+ 1 2).Este operando tem como valor 3, valor esse que é usado pela função no lu-gar do parâmetro x. O corpo da função é então avaliado mas substituindo

22

Page 24: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

todas as ocorrências de x pelo valor 3, i.e., o valor final será o da combina-ção (* 3 3).

Para se perceber a avaliação de combinações que o Lisp emprega, é útildecompor essa avaliação nas suas etapas mais elementares. No seguinteexemplo mostramos o processo de avaliação para a expressão

(quadrado (quadrado (+ 1 2)))

Em cada passo, uma das sub-expressões foi avaliada.

(quadrado (quadrado (+ 1 2)))↓

(quadrado (quadrado 3))↓

(quadrado (* 3 3))↓

(quadrado 9)↓

(* 9 9)↓81

Como dissemos, a definição de funções permite-nos associar um proce-dimento a um nome. Isto implica que o Lisp tem de possuir uma memóriaonde possa guardar a função e a sua associação ao nome dado. Esta memó-ria do Lisp designa-se ambiente.

Note-se que este ambiente apenas existe enquanto estamos a trabalharcom a linguagem. Quando terminamos, perde-se todo o ambiente. Paraevitar perdermos as definições de procedimentos que tenhamos feito, con-vém registá-las num suporte persistente, como seja um ficheiro. Para facili-tar a utilização, o Lisp permite que se avaliem as diversas definições a par-tir de um ficheiro. Por este motivo, o processo usual de trabalho com Lispconsiste em escrever as várias definições em ficheiros embora se continuea usar o avaliador de Lisp para experimentar e testar o correcto funciona-mento das nossas definições.

Exercício 3.6.1 Defina a função dobro que, dado um número, calcula o seu dobro.

23

Page 25: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

3.7 Símbolos

A definição de funções em Lisp passa pela utilização de nomes: nomes paraas funções e nomes para os parâmetros das funções.

Internamente, o Lisp representa os nomes através de símbolos. Cadanome diferente que é lido pelo Lisp acaba por ter um símbolo associadoe é este símbolo que é usado para determinar o significado do nome, porexemplo, qual a função ou qual o parâmetro a que ele diz respeito.

Em Lisp, quase não existem limitações para a escrita de nomes. Umnome como quadrado é tão válido como + ou como 1+2*3 pois o quesepara um nome dos outros elementos de uma combinação são apenas pa-rênteses e espaço em branco.3

No caso do Auto Lisp, os únicos caracteres que não se podem utilizarnos nomes dos símbolos são o abrir e fechar parênteses ( e ), a plica (tam-bém chamada apóstrofo) ’, as aspas ", o ponto . e o ponto e vírgula ;. To-dos os restantes caracteres se podem usar para nomes de funções mas, naprática, a criação de nomes segue algumas regras que convém ter presente:

• Apenas se devem usar as letras do alfabeto, os dígitos, os símbolosaritméticos e alguns caracteres de pontuação, como o ponto, o pontode exclamação e o ponto de interrogação. Por motivos de portabili-dade, convém evitar o uso de caracteres acentuados.

• Se o nome da função é composto por várias palavras, deve-se separaras palavras com traços (-). Por exemplo, uma função que calcula aárea de um círculo poderá ter como nome o símbolo area-circulo.Já os nomes areacirculo, area_circulo e area+circulo serãomenos apropriados.

• Se o nome corresponde a uma interrogação, deve-se terminar o nomecom um ponto de interrogação (?) ou, na tradição Lisp, com a letrap.4 Por exemplo, uma função que indica se um número é par poderáter o nome par?.

• Se a função faz uma conversão entre dois tipos de valores, o nomepoderá ser obtido a partir dos nomes dos tipos com uma seta entreeles a indicar a direcção da conversão. Por exemplo, uma função que

3Dentro do conceito de “espaço em branco” consideram-se os caracteres de espaço, detabulação e de mudança de linha.

4Esta letra é a abreviatura de predicado, um tipo de função que iremos estudar mais àfrente.

24

Page 26: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

converte euros para libras poderá ter como nome euros->librasou, ainda melhor, libras<-euros.

Exercício 3.7.1 Indique um nome apropriado para cada uma das seguintes funções:

1. Função que calcula o volume de uma esfera.2. Função que indica se um número é primo.3. Função que converte uma medida em centímetros para polegadas.

3.8 Avaliação de Símbolos

Vimos que todos os outros elementos primitivos que apresentámos até agora,nomeadamente, os números e as cadeias de caracteres avaliavam para elespróprios, i.e., o valor de uma expressão composta apenas por um elementoprimitivo é o próprio elemento primitivo. No caso dos símbolos, isso já nãoé verdade.

Lisp atribui um significado muito especial aos símbolos. Reparemosque, quando definimos uma função, o nome da função é um símbolo. Osparâmetros formais da função também são símbolos. Quando escrevemosuma combinação, o avaliador de Lisp usa a definição de função que foiassociada ao símbolo que constitui o primeiro elemento da combinação.Isto quer dizer que o valor do primeiro símbolo de uma combinação é afunção que lhe está associada. Admitindo que tínhamos definido a funçãoquadrado tal como vimos na secção 3.6, podemos verificar este comporta-mento experimentando as seguintes expressões:

_$ (quadrado 3)9_$ quadrado#<USUBR @1d4c66f4 QUADRADO>

Como se pode ver pelo exemplo anterior, o valor do símbolo quadradoé uma entidade que o Lisp descreve usando uma notação especial. A en-tidade em questão é, como vimos, uma função. O mesmo comportamentoocorre para qualquer outra função pré-definida na linguagem:5

_$ +#<SUBR @0a87c5a8 +>_$ *#<SUBR @0a87c588 *>

5Um olhar mais atento encontrará uma pequena diferença: no caso do quadrado, afunção associada é do tipo USUBR enquanto que nos casos do + e * as funções associadassão do tipo SUBR. A diferença entre estes dois tipos está relacionada com o facto de asSUBRs estarem compiladas, permitindo a sua invocação de forma mais eficiente. O termoSUBR é uma abreviatura de subroutine.

25

Page 27: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Como vimos com o + e o *, alguns dos símbolos estão pré-definidos nalinguagem. Por exemplo, o símbolo PI também existe pré-definido comuma aproximação do valor de π.

_$ pi3.141519

No entanto, quando o avaliador está a avaliar o corpo de uma função,o valor de um símbolo especificado nos parâmetros da função é o argu-mento correspondente na invocação da função. Assim, na combinação(quadrado 3), depois de o avaliador saber que o valor de quadrado éa função por nós definida atrás e que o valor de 3 é 3, o avaliador passaa avaliar o corpo da função quadrado mas assumindo que, durante essaavaliação, o nome x, sempre que for necessário, irá ter como valor precisa-mente o mesmo 3 que foi associado ao parâmetro x.

Exercício 3.8.1 Defina a função radianos<-graus que recebe uma quantidade angularem graus e calcula o valor correspondente em radianos. Note que 180 graus correspondema π radianos.

Exercício 3.8.2 Defina a função graus<-radianos que recebe uma quantidade angularem radianos e calcula o valor correspondente em graus.

Exercício 3.8.3 Defina a função que calcula o perímetro de uma circunferência de raio r.

3.9 Funções de Múltiplos Parâmetros

Já vimos e definimos várias funções em Lisp. Até agora, todas as que de-finimos tinham um único parâmetro mas, obviamente, é possível definirfunções com mais do que um parâmetro.

Por exemplo, a área A de um triângulo de base b e altura c define-sematematicamente por A(b, c) = b·c

2 . Em Lisp, teremos:

(defun A (b c) (/ (* b c) 2))

Como se pode ver, a definição da função em Lisp é idêntica à definiçãocorrespondente em Matemática, com a diferença de os operadores se usa-rem de forma prefixa e o símbolo de definição matemática = se escreverdefun. No entanto, contrariamente ao que é usual ocorrer em Matemá-tica, os nomes que empregamos em Lisp devem ter um significado claro.Assim, ao invés de se escrever A é preferível escrever area-triangulo.Do mesmo modo, ao invés de se escrever b e c, seria preferível escreverbase e altura. Tendo estes aspectos em conta, podemos apresentar umadefinição mais legível:

26

Page 28: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(defun area-triangulo (base altura)(/ (* base altura) 2))

Quando o número de definições aumenta torna-se particularmente im-portante para quem as lê que se perceba rapidamente o seu significado e,por isso, é de crucial importância que se faça uma boa escolha de nomes.

Exercício 3.9.1 Defina uma função que calcula o volume de um paralelipípedo a partir doseu comprimento, altura e largura. Empregue nomes suficientemente claros.

Exercício 3.9.2 Defina a função media que calcula o valor médio entre dois outros valores.Por exemplo (media 2 3)→2.5.

3.10 Encadeamento de Funções

Todas funções por nós definidas são consideradas pelo avaliador de Lispem pé de igualdade com todas as outras definições. Isto permite que elaspossam ser usadas para definir ainda outras funções. Por exemplo, apóstermos definido a função quadrado, podemos definir a função que calculaa área de um círculo de raio r através da fórmula π · r2.

(defun area-circulo (raio)(* pi (quadrado raio)))

Durante a avaliação de uma expressão destinada a computar a àrea deum círculo, a função quadrado acabará por ser invocada. Isso é visível naseguinte sequência de passos de avaliação:

(area-circulo 2)(* pi (quadrado 2))(* 3.141519 (quadrado 2))(* 3.141519 (* 2 2))(* 3.141519 4)12.566076

Exercício 3.10.1 Defina a função que calcula o volume de um cilindro com um determi-nado raio e comprimento. Esse volume corresponde ao produto da área da base pelo com-primento do cilindro.

3.11 Funções Pré-Definidas

A possibilidade de se definirem novas funções é fundamental para aumen-tarmos a flexibilidade da linguagem e a sua capacidade de se adaptar aosproblemas que pretendemos resolver. As novas funções, contudo, precisam

27

Page 29: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

de ser definidas à custa de outras que, ou foram também por nós definidasou, no limite, já estavam pré-definidas na linguagem.

Isto mesmo se verifica no caso da função area-circulo que defini-mos acima: ela está definida à custa da função quadrado (que foi tambémpor nós definida) e à custa da operação de multiplicação. No caso da fun-ção quadrado, ela foi definida com base na operação de multiplicação. Aoperação de multiplicação que, em última análise, é a base do funciona-mento da função area-circulo é, na realidade, uma função pré-definidado Lisp.

Como iremos ver, Lisp providencia um conjunto razoavelmente grandede funções pré-definidas. Em muitos casos, elas são suficientes para o quepretendemos mas, em geral, não nos devemos coibir de definir novas fun-ções sempre que acharmos necessário.

A Tabela 2 apresenta uma selecção de funções matemáticas pré-definidasdo Auto Lisp. Note-se que, devido às limitações sintáticas do Auto Lisp (eque são comuns a todas as outras linguagens de programação), há várioscasos em que uma função em Auto Lisp emprega uma notação diferentedaquela que é usual em matemática. Por exemplo, a função raiz quadrada√x escreve-se como (sqrt x). O nome sqrt é uma contracção do In-

glês square root e contracções semelhantes são empregues para várias outrasfunções. Por exemplo, a função valor absoluto |x| escreve-se (abs x) (deabsolute value), a função parte inteira bxc escreve-se (fix x) (de fixed point)e a função potência xy que se escreve (expt x y) (de exponential). A Ta-bela 3 mostra as equivalências mais relevantes entre invocações de funçõesem Auto Lisp e as correspondentes invocações na Matemática.

A Tabela 4 apresenta uma selecção de funções sobre strings pré-definidasdo Auto Lisp. À medida que formos apresentando novos tópicos do AutoLisp iremos explicando outras funções pré-definidas que sejam relevantespara o assunto.

Exercício 3.11.1 Como pode verificar pelas Tabelas 2 e 3, em Auto Lisp, uma multiplicaçãosem argumentos produz o valor zero, tal como acontece no caso de uma divisão sem argu-mentos. No entanto, os matemáticos contestam este resultado, afirmando que está erradoe que o valor correcto deveria ser outro. Concorda? Em caso afirmativo, qual deveria ser ovalor correcto?

Exercício 3.11.2 Embora o seno (sin) e o cosseno (cos) sejam funções pré-definidas emAuto Lisp, a tangente (tan) não é. Defina-a a partir da fórmula tanx = sin x

cos x.

Exercício 3.11.3 Do conjunto das funções trigonométricas inversas, o Auto Lisp apenas pro-videncia o arco tangente (atan). Defina também as funções arco-seno (asin) e arco-cosseno

28

Page 30: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(acos), cujas definições matemáticas são:

asinx = atanx√

1− x2

acosx = atan

√1− x2

x

Exercício 3.11.4 A função fix permite truncar um número real, produzindo o número in-teiro que se obtém pela eliminação da parte fraccionária desse real. Defina a função roundque permite arredondar um número real, i.e., produzir o inteiro que é mais próximo dessenúmero real.

Exercício 3.11.5 Para além da função round que arredonda para o inteiro mais próximoe da função fix que arredonda “para baixo,” é usual considerar ainda a função ceilingque arrendonda “para cima.” Defina esta função.

Exercício 3.11.6 Traduza as seguintes expressões matemáticas para Auto Lisp:

1.q

1

log 2|(3−9 log 25)|

2.cos4 2√

5atan 3

3. 12

+√

3 + sin52 2

Exercício 3.11.7 Traduza as seguintes expressões Auto Lisp para a notação 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))

Exercício 3.11.8 Defina o predicado impar? que, dado um número, testa se ele é ímpar,i.e., se o resto da divisão desse número por dois é um. Para calcular o resto da divisão deum número por outro, utilize a função pré-definida rem.

Exercício 3.11.9 Em várias actividades é usual empregarem-se expressões padronizadas.Por exemplo, se o aluno Passos Dias Aguiar pretende obter uma certidão de matrícula dauniversidade que frequenta, terá de escrever uma frase da forma:

Passos Dias Aguiar vem respeitosamente pedir a V. Exa. que se dignepassar uma certidão de matrícula.

Por outro lado, se a aluna Maria Gustava dos Anjos pretende um certificado de habili-tações, deverá escrever:

Maria Gustava dos Anjos vem respeitosamente pedir a V. Exa. que sedigne passar um certificado de habilitações.

29

Page 31: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Para simplificar a vida destas pessoas, pretende-se que implemente uma função de-nominada requerimento que, convenientemente parameterizada, gera uma string com afrase apropriada para qualquer um dos fins anteriormente exemplificados e também paraoutros do mesmo género que possam vir a ser necessários. Teste a sua função para garantirque consegue reproduzir os dois exemplos anteriores passando o mínimo de informaçãonos argumentos da função.

Exercício 3.11.10 Também na actividade da Arquitectura, é usual os projectos necessita-rem de informações textuais escritas numa forma padronizada. Por exemplo, considere asseguintes três frases contidas nos Cadernos de Encargos de três diferentes projectos:

Toda a caixilharia será metálica, de alumínio anodizado, cor natural, cons-truída com os perfis utilizados pela Serralharia do Corvo (ou semelhante),sujeitos a aprovação da Fiscalização.

Toda a caixilharia será metálica, de alumínio lacado, cor branca, cons-truída com os perfis utilizados pela Technal (ou semelhante), sujeitos a apro-vação da Fiscalização.

Toda a caixilharia será metálica, de aço zincado, preparado com primá-rios de aderência, primário epoxídico de protecção e acabamento com esmalteSMP, cor 1050-B90G (NCS), construída com os perfis standard existentes nomercado, sujeitos a aprovação da Fiscalização.

Defina uma função que, convenientemente parameterizada, gera a string adequadapara os três projectos anteriores, tendo o cuidado de a generalizar para qualquer outrasituação do mesmo género.

3.12 Aritmética de Inteiros em Auto Lisp

Vimos que o Auto Lisp disponibiliza, para além dos operadores aritméticosusuais, um conjunto de funções matemáticas. No entanto, há que ter emconta que existem diferenças substanciais entre o significado matemáticodestas operações e a sua implementação no Auto Lisp.

Um primeiro problema importante tem a ver com a gama de inteiros.Em Auto Lisp, os inteiros são representados com apenas 32 bits de infor-mação.6 Isto implica que apenas se conseguem representar inteiros desde−2147483647 até 2147483647. Para tornar a situação ainda mais problemá-tica, embora exista esta limitação, quando ela não é respeitada o Auto Lispnão emite qualquer aviso. Este comportamento é usual na maioria das lin-guagens de programação e está relacionado com questões de performance.7

6Em AutoCad, a gama de inteiros é ainda mais pequena pois a sua representação apenasusa 16 bits, permitindo apenas representar os inteiros de −32768 a 32767. Isto não afecta oAuto Lisp excepto quando este tem de passar inteiros para o AutoCad.

7Curiosamente, a maioria dos dialectos de Lisp (mas não o Auto Lisp) não apresenta estecomportamento, preferindo representar números inteiros com dimensão tão grande quantofor necessário.

30

Page 32: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

−∞ +∞−2147483648 −2−1 0 +1 +2 +2147483647

−2−1 0 +1

+2

+2147483647−2147483648

Figura 1: A recta infinita dos inteiros empregue em aritmética e o círculodos inteiros modulares empregues em Auto Lisp.

Infelizmente, a performance tem como preço o poder originar resultadosaparentemente bizarros:

_$ (+ 2147483647 1)-2147483648

Este resultado surge porque no Auto Lisp, na realidade, as operaçõesaritméticas com inteiros são modulares. Isto implica que a sequência dos in-teiros não corresponde a uma linha infinita nas duas direcção, antes corres-pondendo a um círculo em que a seguir ao maior número inteiro positivoaparece o menor número inteiro negativo. Este comportamento encontra-se explicado na Figura 1.

Um segundo problema que já referimos anteriormente está no facto deo Auto Lisp não saber representar fracções. Isto implica que uma divisãode dois inteiros não corresponde à divisão matemática mas sim a uma ope-ração substancialmente diferente denominada divisão inteira: uma divisãoem que a parte fraccional do resultado é eliminada, i.e., apenas se considerao quociente da divisão, eliminando-se o resto. Assim, (/ 7 2) é 3 e não 7/2ou 3.5. Obviamente, isto inviabiliza algumas equivalências matemáticasó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 aleitura de um número inteiro que excede a gama dos inteiros implica a sua

31

Page 33: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

conversão automatica para o tipo real.8 Neste caso, o avaliador do AutoLisp nunca chega a “ver” o número inteiro pois ele foi logo convertidopara real na leitura. Esse comportamento é visível no seguinte exemplo:

_$ 12345678901234567890_$ 123456789011.23457e+010

Também este aspecto do Auto Lisp pode ser fonte de comportamentosbizarros, tal como é demonstrado pelo seguinte exemplo:

_$ (+ 2147483646 1)2147483647_$ (+ 2147483647 1)-2147483648_$ (+ 2147483648 1)2.14748e+009

É importante salientar que a conversão de inteiro para real que é visívelna última interacção é feita logo na leitura.

Exercício 3.12.1 Calcule o valor das seguintes expressões Auto Lisp:

1. (- 1)

2. (- 1 1)

3. (- 1 1 1)

4. (/ 1 1)

5. (/ 1 2)

6. (/ (* 3 2) 2)

7. (* (/ 3 2) 2)

8. (/ (/ (/ 8 2) 2) 2)

9. (/ 8 (/ 2 (/ 2 2)))

10. (+ (/ 1 2) (/ 1 2))

Exercício 3.12.2 Explique o seguinte comportamento do Auto Lisp:9

8Note-se que estamos apenas a falar da leitura de números. Como já vimos, as operaçõesaritméticas usuais não apresentam este comportamento.

9Este exemplo mostra que, em Auto Lisp, há um inteiro que não pode ser lido mas quepode ser produzido como resultado de operações aritméticas. É importante salientar queeste comportamento verdadeiramente bizarro é exclusivo do Auto Lisp e não se verifica emmais nenhum dialecto de Lisp.

32

Page 34: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

_$ (- -2147483647 1)-2147483648_$ (- -2147483648 1)-2.14748e+009_$ (- -2147483647 2)2147483647

Exercício 3.12.3 A área A de um pentágono regular inscrito num círculo de raio r é dadapela fórmula

A =5

8r2

q10 + 2

√5

Defina uma função Auto Lisp que calcule essa área.

Exercício 3.12.4 Defina uma função que calcula o volume de um elipsóide de semi-eixos a,b e c. Esse volume pode ser obtido pela fórmula V = 4

3πabc.

3.13 Aritmética de Reais em Auto Lisp

Em relação aos reais, o seu comportamento é mais próximo do que se con-sidera matematicamente correcto mas, ainda assim, há vários problemascom que é preciso lidar.

A gama dos reais vai desde −4.94066 · 10−324 até 1.79769 · 10+308. Se oAuto Lisp tentar ler um número real que excede esta gama ele é imediata-mente convertido para um número especial que representa o infinito:

_$ 2e4001.#INF_$ -2e400-1.#INF

Note-se que 1.#INF ou -1.#INF é a forma do Auto Lisp indicar umvalor que excede a capacidade de representação de reais do computador.Não é infinito, como se poderia pensar, mas apenas um valor excessiva-mente grande para as capacidades do Auto Lisp. Do mesmo modo, quandoalguma operação aritmética produz um número que excede a gama dos re-ais, é simplesmente gerada a representação do infinito.

_$ 1e3001.0e+300_$ 1e1001.0e+100_$ (* 1e300 1e100)1.#INF

Nestes casos, em que o resultado de uma operação é um número queexcede as capacidades da máquina, dizemos que ocorreu um overflow.

33

Page 35: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

As operações com números reais têm a vantagem de a maioria dos com-putadores actuais conseguirem detectar o overflow de reais e reagirem emconformidade (gerando um erro ou simplesmente produzindo uma repre-sentação do infinito). Como vimos anteriormente, se se tivessem usadonúmeros inteiros, então o overflow não seria sequer detectado, produzindocomportamentos aparentemente bizarros, como, por exemplo, o produtode dois números positivos ser um número negativo.

Há ainda dois outros problemas importantes relacionados com reais:erros de arredondamento e redução de precisão na escrita. A título deexemplo, consideremos a óbvia igualdade matemática (4

3 − 1) · 3− 1 = 0 ecomparemos os resultados que se obtêm 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 consegueobter o resultado correcto. No caso dos inteiros, o problema é causado peladivisão inteira de 4 por 3 que produz 1. No caso dos reais, o problema écausado por erros de arrendondamento: 4/3 não é representável com umnúmero finito de dígitos. Este erro de arrendondamento é então propagadonas restantes operações produzindo um valor que, embora não seja zero,está muito próximo.

Obviamente, como o resultado da avaliação com reais é suficientementepequeno, podemos convertê-lo para o tipo inteiro (aplicando-lhe uma trun-catura com a função fix) e obtemos o resultado correcto:

_$ (fix (- (* (- (/ 4.0 3.0) 1.0) 3.0) 1.0))0

No entanto, esta “solução” também tem problemas. Consideremos adivisão 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 binário derepresentação e, neste sistema, não é possível representar os números 0.6 e0.2 com um número finito de dígitos binários e, consequentemente, ocor-rem erros de arredondamento. Por este motivo, o resultado da divisão, em

34

Page 36: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

vez de ser 3, é 2.999999999999999555910790149937, embora o Auto Lisp oapresente como 3.0. No entanto, ao eliminarmos a parte fraccionária com afunção fix, o que fica é apenas o inteiro 2.

Igualmente perturbante é o facto de, embora 0.4 · 7 = 0.7 · 4 = 2.8,em Auto Lisp, (* 0.4 7) 6= (* 0.7 4): ambas as expressões têm um va-lor que é escrito pelo Auto Lisp como 2.8 mas há diferentes erros de ar-rendondamento cometidos nas duas expressões que tornam os resultadosdiferentes.

Note-se que, mesmo quando não há erros de arrendondamento nas ope-rações, a reduzida precisão com que o Auto Lisp escreve os resultados podeinduzir-nos em erro. Por exemplo, embora internamente o Auto Lisp saibaque (/ 1.000001 10) produz 0.1000001, ele apenas escreve 0.1 comoresultado.

Exercício 3.13.1 Pretende-se criar um lanço de escada com n espelhos capaz de vencer umadeterminada altura a em metros. Admitindo que cada degrau tem uma altura do espelho he uma largura do cobertor d que verificam a proporção

2h+ d = 0.64

defina uma função que, a partir da altura a vencer e do número de espelhos, calcula ocomprimento do lanço de escada.

3.14 Símbolos e Avaliação

Vimos que os símbolos avaliam para aquilo a que estiverem associados nomomento da avaliação. Por este motivo, os símbolos são usados para darnomes às coisas. O que é mais interessante é que os símbolos são, eles pró-prios, coisas!

Para percebermos esta característica dos símbolo vamos apresentar umafunção pré-definida do Auto Lisp que nos permite saber o tipo de uma en-tidade qualquer: type. Consideremos a seguinte interacção:

_$ (type 1)INT_$ (type "Bom dia!")STR_$ (type pi)REAL_$ (type quadrado)USUBR_$ (type +)SUBR

35

Page 37: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Como podemos ver, a função type devolve-nos o tipo do seu argu-mento: INT para inteiros, STR para strings, REAL para reais, etc.

Mas o que são estes resultados—INT, STR, REAL, etc— que foram de-volvidos pela função type? Que tipo de objectos são? Para responder àquestão, o melhor é usar a mesmíssima função type:

_$ (type pi)REAL_$ (type (type pi))SYM

SYM é a abreviatura de symbol, indicando que o objecto que é devol-vido pela função type é um símbolo. Note-se que, contrariamente ao queacontece com o símbolo pi que está associado ao número 3.141519 . . . , ossímbolos REAL, INT, STR, etc., não estão associados a nada, eles apenas sãousados como representação do nome de um determinado tipo de dados.

Se os valores devolvidos pela função type são objectos do tipo símbolo,então deverá ser possível designá-los, tal como designamos os números ouas strings. Mas qual será o modo de o fazermos? Uma hipótese (errada) se-ria escrevê-lo tal como escrevemos números ou strings. Acontece que isto épossível no caso dos números e strings pois eles avaliam para eles próprios.Já no caso dos símbolos, sabemos que não avaliam para eles próprios, an-tes avaliando para as entidades a que estão associados naquele momento.Assim, se quisermos designar o símbolo pi, não bastará escrevê-lo numaexpressão pois o que irá resultar após a sua avaliação não será um símbolomas sim o número 3.141519 . . . que é o valor desse símbolo.

Para ultrapassar este problema precisamos de, por momentos, alterar asemântica habitual que o Lisp atribui aos símbolos. Essa semântica, recordemo-nos, é a de que o valor de um símbolo é a entidade a que esse símbolo estáassociado nesse momento e esse valor surge sempre que o Lisp avalia osímbolo. Para alterarmos essa semântica, precisamos de indicar ao Lispque não queremos que ele avalie um determinado símbolo, i.e., queremosque ele trate o símbolo como ele é, sem o avaliar. Para isso, o Lisp dis-ponibiliza a forma quote. Esta forma, que recebe um único argumento,tem uma semântica simplicíssima: devolve o argumento sem este ter sidoavaliado. Reparemos na seguinte interacção:

_$ pi3.14159_$ (quote pi)PI_$ (+ 1 2 3)

36

Page 38: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

6_$ (quote (+ 1 2 3))(+ 1 2 3)

Como se vê, qualquer que seja o argumento α da expressão (quote α),o valor da expressão é o próprio α sem ter sido avaliado.

A razão de ser do quote está associada à distinção que existe entre asfrases “Diz-me o teu nome” e “Diz-me ‘o teu nome’ ”. No primeiro casoa frase tem de ser completamente interpretada para que o ouvinte possadizer qual é o seu próprio nome. No segundo caso, as plicas estão lá paraindicar ao ouvinte que ele não deve interpretar o que está entre plicas edeve limitar-se a dizer a frase “o teu nome”. As plicas servem, pois, paradistinguir o que deve ser tomado como é e o que deve ser interpretado.

Para simplificar a escrita de formas que empregam o quote, o Lispdisponibiliza uma abreviatura que tem exactamente o mesmo significado:a plica (’). Quando o Lisp está a fazer a leitura de uma expressão e encontraalgo da forma ’α, aquilo que é lido é, na realidade, (quote α). Assim,temos:

_$ ’piPI_$ ’(+ 1 2 3)(+ 1 2 3)

Exercício 3.14.1 Qual é o significado da expressão ’’pi?

4 Combinação de Dados

Vimos, nas secções anteriores, alguns dos tipos de dados pré-definidos emAuto Lisp. Em muitos casos, esses tipos de dados são os necessários esuficientes para nos permitir criar os nossos programas mas, noutros casos,será necessário introduzirmos novos tipos de dados. Nesta secção iremosestudar o modo de o fazermos e iremos exemplificá-lo com um tipo dedados que nos será particularmente útil: coordenadas.

4.1 Coordenadas

A Arquitectura pressupõe a localização de elementos no espaço. Essa loca-lização expressa-se em termos do que se designa por coordenadas: as coor-denadas de um ponto identificam univocamente esse ponto no espaço.

Se o espaço for bi-dimensional (abreviadamente, 2D), cada ponto é iden-tificado por duas coordenadas. Se o espaço for tri-dimensional (3D), cada

37

Page 39: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

φ

x

Figura 2: Coordenadas rectangulares e polares.

ponto é identificado por três coordenadas. Por agora, vamos considerarapenas o caso de coordenadas bi-dimensionais.

Existem vários sistemas de coordenadas bi-dimensionais possíveis masos mais usais são o sistema de coordenadas rectangulares e o sistemas decoordenadas polares, representados na Figura 2. No sistema de coordena-das rectangulares, esse par de números designa a abcissa x e a ordenada y.No sistema de coordenadas polares, esse par de números designa o raio vec-tor ρ e o ângulo polar φ. Em qualquer caso, as coordenadas bi-dimensionaissão descritas por um par de números.

Como vimos nas secções anteriores, o Auto Lisp sabe lidar com o con-ceito de números. Vamos agora ver que ele também sabe lidar com o con-ceito de par.

4.2 Pares

Em Lisp, podemos criar pares através da função pré-definida cons. Estafunção, cujo nome é a abreviatura da palavra construct, aceita quaisquerduas entidades como argumentos e produz um par com essas duas entida-des. Tradicionalmente, é usual dizer que o par é um cons.10

Eis um exemplo da criação de um par de números:

_$ (cons 1 2)(1 . 2)

Como podemos ver pela interacção anterior, quando o Lisp pretendeescrever o resultado da criação de um par, ele começa por escrever um

10O cons é para o Lisp o mesmo que as tabelas (arrays) e estruturas (records, structs)são para as outras linguagens como Pascal ou C. Na prática, o cons é um mecanismo deagregação de entidades.

38

Page 40: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

abrir parênteses, depois escreve o primeiro elemento do par, depois escreveum ponto de separaração, depois escreve o segundo elemento do par e,finalmente, escreve um fechar parênteses. Esta notação denomina-se “parcom ponto” ou, no original, dotted pair.

Quando o Lisp cria um par de elementos, cria uma associação internaentre esses elementos que podemos representar graficamente como umacaixa dividida em duas metades, cada uma apontando para um dos ele-mentos. Por exemplo, o par anterior pode ser representado graficamenteda seguinte forma:

1 2

A representação gráfica anterior denomina-se notação de “caixa e pon-teiro” precisamente porque mostra os pares como caixas com ponteirospara os elementos dos pares.

Uma vez que a construção de um par é feita usando uma função, a suainvocação segue as mesmas regras de avaliação de todas as outras invo-cações de funções, ou seja, as expressões que constituem os argumentossão avaliadas e são os resultados dessas avaliações que são usados comoelementos 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 propósito deste último exemplo, note-se a diferença entre o pontorelativo à parte fraccionária do primeiro número e o ponto relativo à sepa-ração dos elementos do par. Na primeira ocorrência, o ponto faz parte dasintaxe do número fraccionário e não pode ter espaços. Na segunda ocorrên-cia, o ponto faz parte da sintaxe dos pares e tem de ter espaços.

A partir do momento em que temos um par de entidades, podemos es-tar interessados em saber quais são os elementos do par. Em Lisp, dado umpar de entidades (um “cons”) podemos obter o primeiro elemento do parusando a função car e podemos obter o segundo elemento do par usandoa função cdr.

39

Page 41: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

_$ (car (cons 1 2))1_$ (cdr (cons 1 2))2

Note-se que aplicar o car ou o cdr a um cons não afecta esse cons,apenas diz qual é o primeiro ou segundo elemento do cons. Em termosda representação gráfica de “caixa e ponteiro,” a aplicação das funções care cdr corresponde, simplesmente, a seguir os apontadores da esquerda edireita, respectivamente.

Os nomes car e cdr têm raizes históricas e, embora possa não parecer,são relativamente fáceis de decorar. Uma mnemónica que pode ajudar épensar que o “cAr” obtém o elemento que vem “Antes” e o “cDr” obtém oelemento que vem “Depois.”

Uma vez que a função cons forma pares com os seus argumentos, éigualmente possível formar pares de pares. Os seguintes exercícios exem-plificam esta situação.

Exercício 4.2.1 Qual o resultado da avaliação da expressão (cons (cons 1 2) 3)?

Exercício 4.2.2 Qual o resultado da avaliação da expressão (car (cons (cons 1 2) 3))?

Exercício 4.2.3 Qual o resultado da avaliação da expressão (cdr (cons (cons 1 2) 3))?

4.3 Operações com Coordenadas

A partir do momento em que sabemos construir pares, podemos criar coor-denadas e podemos definir operações sobre essas coordenadas. Para criar-mos coordenadas podemos simplesmente juntar num par os dois númerosque representam a abcissa e a ordenada. Por exemplo, o ponto do espaçocartesiano (1, 2) pode ser construído através de:

_$ (cons 1 2)(1 . 2)

Uma vez que estamos a fazer um par que contém, primeiro, a abcissa e,depois, a ordenada, podemos obter estes valores usando, respectivamente,as funções car e cdr.

Para melhor percebermos a utilização destas funções, imaginemos quepretendemos definir uma operação que mede a distância d entre os pontosP0 = (x0, y0) e P1 = (x1, y1) que podemos ver na Figura 3. A distância dcorresponde, logicamente, ao comprimento da recta que une P0 a P1.

40

Page 42: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

P0

P1

d

x0

y0

x1

y1

Figura 3: Distância entre dois pontos.

A aplicação do teorema de Pitágoras permite-nos determinar a distân-cia d em termos das coordenadas dos pontos P0 a P1:

d =√

(x1 − x0)2 + (y1 − y0)2

A tradução desta fórmula para Auto Lisp consiste da seguinte defini-ção:

(defun distancia-2d (p0 p1)(sqrt (+ (quadrado (- (car p1) (car p0)))

(quadrado (- (cdr p1) (cdr p0))))))

Podemos agora experimentar a função com um caso concreto:

_$ (distancia-2d (cons 2 3) (cons 8 6))6.7082

4.4 Abstracção de Dados

Embora tenhamos pensado na operação distancia-2d como uma funçãoque recebe as coordenadas de dois pontos, quer quando observamos a de-finição da função, quer quando observamos a sua utilização subsequente,o que vemos é a invocação das operações cons, car e cdr e, consequente-mente, nada nos diz que a função esteja a lidar com coordenadas. Embora oconceito de coordenadas esteja presente nos nossos pensamentos, os nossosprogramas apenas mostram que estamos a construir e a manipular pares.

41

Page 43: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Esta diferença entre os conceitos que temos na nossa cabeça e os queempregamos na programação torna-se ainda mais evidente quando pen-samos noutras entidades matemáticas que, tal como as coordenadas, tam-bém agrupam elementos mais simples. Um número racional, por exemplo,define-se como um par de dois números inteiros, o numerador e o denomi-nador. À semelhança do que fizemos com as coordenadas, também pode-riamos criar um número racional em Auto Lisp à custa da função cons epoderiamos seleccionar o numerador e o denominador à custa das funçõescar e cdr. Outro exemplo será a implementação de números complexos.Estes também são constituídos por pares de números reais e também pode-riam ser implementados à custa das mesma funções cons, car e cdr.

À medida que formos implementando em Auto Lisp as funções quemanipulam estes conceitos, a utilização sistemática das funções cons, care cdr fará com que seja cada vez mais difícil perceber qual ou quais ostipo de dados a que se destina uma determinada função. De facto, a partirapenas das funções cons, car e cdr não podemos saber se estamos a lidarcom coordenadas, racionais, complexos ou qualquer outro tipo de dadosque tenhamos implementado em termos de pares.

Para resolvermos este problema é necessário preservarmos no AutoLisp o conceito original que pretendemos implementar. Para isso, temosde abstrair a utilização que fazemos dos pares, “escondendo-a” no interiorde funções que representem explicitamente os conceitos originais. Vamosagora exemplificar esta abordagem reconsiderando o conceito de coordena-das cartesianas bi-dimensionais e introduzindo funções apropriadas paraesconder a utilização dos pares.

Assim, para construirmos as coordenadas (x, y) a partir dos seus com-ponentes x e y, ao invés de usarmos directamente a função cons vamosdefinir uma nova função que vamos denominar de xy:11

(defun xy (x y)(cons x y))

A construção de coordenadas bi-dimensionais por intermédio da fun-ção xy é apenas o primeiro passo para abstrairmos a utilização dos pares.O segundo passo é a criação de funções que acedem à abcissa x e à orde-nada y das coordenadas (x, y). Para isso, vamos definir, respectivamente,

11Naturalmente, podemos considerar outro nome igualmente apropriado como, porexemplo, coordenadas-cartesianas-2d. Contudo, como é de esperar que tenhamosfrequentemente de criar coordenadas, é conveniente que adoptemos um nome suficiente-mente curto e, por isso, vamos adoptar o nome xy.

42

Page 44: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

as funções cx e cy como abreviaturas de coordenada x e coordenada y:12

(defun cx (c)(car c))

(defun cy (c)(cdr c))

As funções xy, cx e cy constituem uma abstracção das coordenadas bi-dimensionais que nos permitem escrever as funções que manipulam coor-denadas sem termos de pensar na sua implementação em termos de pares.Esse facto torna-se evidente quando reescrevemos a função distancia-2dem termos destas novas funções:

(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 versãodesta função, a leitura da função dá agora uma ideia clara do que ela faz.Ao invés de termos de pensar em termos de car e cdr, vemos que a funçãolida com as coordenadas x e y. A utilização da função também mostraclaramente que o que ela está a manipular são coordenadas:

_$ (distancia-2d (xy 2 3) (xy 8 6))6.7082

A introdução das operações de coordenadas xy, cx e cy não só tornamais claro o significado dos nossos programas como facilita bastante adefinição de novas funções. Agora, ao invés de termos de nos lembrarque as coordenadas são pares cujo primeiro elemento é a abcissa e cujosegundo elemento é a ordenada, basta-nos pensar nas operações básicasde coordenadas e definir as funções que pretendermos em termos delas.Por exemplo, imaginemos que pretendemos definir uma operação que faz“deslocar” um ponto de uma determinada distância, expressa em termosde um comprimento ∆x e de uma altura ∆y, tal como está apresentado naFigura 4. Como será evidente pela Figura, sendo P = (x, y), então tere-mos P ′ = (x + ∆x, y + ∆y). Para simplificar o uso desta função, vamos

12Tal como a função xy poderia ter um nome mais explícito, também as funçõesque acedem à abcissa e à ordenada se poderiam denominar abcissa e ordenada oucoordenada-x e coordenada-y ou qualquer outro par de nomes suficientemente claro.No entanto, sendo as coordenadas um tipo de dados com muito uso, mais uma vez se tor-nará vantajoso que empreguemos nomes curtos.

43

Page 45: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

P

∆y

∆x

P ′

Figura 4: Deslocamento de um ponto.

denominá-la de +xy. Naturalmente, ela precisa de receber, como parâme-tros, o ponto de partida P e os incrementos ∆x e ∆y que iremos denominarde dx e dy, respectivamente.

A definição da função fica então:

(defun +xy (p dx dy)(xy (+ (cx p) dx)

(+ (cy p) dy)))

Uma vez que esta função recebe coordenadas como argumento e pro-duz coordenadas como resultado, ela constitui outra importante adição aoconjunto de operações disponíveis para lidar com coordenadas. Natural-mente, podemos usar a função +xy para definir novas funções como, porexemplo, os casos particulares de deslocamento horizontal e vertical que seseguem:

(defun +x (p dx)(+xy p dx 0))

(defun +y (p dy)(+xy p 0 dy))

4.5 Coordenadas Tri-Dimensionais

As coordenadas bi-dimensionais localizam pontos num plano. A localiza-ção de pontos no espaço requer coordenadas tri-dimensionais. Tal comoacontecia com as coordenadas bi-dimensionais, também existem vários sis-temas de coordenadas tri-dimensionais, nomeadamente, o sistema de co-ordenadas rectangulares, o sistema de coordenadas cilíndricas e o sistema

44

Page 46: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

y

z

x

P

x

z

y

Figura 5: Coordenadas Cartesianas

de coordenadas esféricas. Em qualquer deles, a localização de um ponto noespaço é feita à custa de três parâmetros independentes. As coordenadastri-dimensionais são, por isso, triplos de números.

Nesta secção vamos debruçar-nos apenas sobre o sistema de coorde-nadas rectangulares, também conhecidas por coordenadas Cartesianas emhonra ao seu inventor: René Descartes. Estas coordenadas estão represen-tadas na Figura 5.

Como vimos na secção anterior, o Auto Lisp disponibiliza a operaçãocons para permitir formar pares de elementos, o que nos permitiu tradu-zir as coordenadas bi-dimensionais da geometria para pares de númerosem Auto Lisp. Agora, a situação é ligeiramente mais complexa pois o AutoLisp não disponibiliza nenhuma operação capaz de fazer triplos de núme-ros. Ou quádruplos. Ou quíntuplos. Ou, na verdade, qualquer outro tipode tuplo para além dos duplos.

Na realidade, esta aparente limitação do Auto Lisp é perfeitamente jus-tificada pois é trivial, a partir de pares, formarmos qualquer tipo de agrupa-mento que pretendamos. Um triplo pode ser feito à custa de dois pares: umcontendo dois elementos e outro contendo este par e o terceiro elemento.Um quádruplo pode ser feito à custa de três pares: um par para cada doiselementos e um terceiro par contendo os dois pares anteriores. Um quín-tuplo pode ser feito à custa de quatro pares: três pares para formar umquádruplo e um quarto par para juntar o quádruplo ao quinto elemento.Agrupamentos com maior número de elementos podem ser formados sim-plesmente seguindo esta estratégia.

45

Page 47: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Uma vez que um triplo de números se pode implementar à custa dedois pares, vamos usar os mesmos dois pares para implementar coordena-das tri-dimensionais. Para abstrair a utilização destes pares, vamos definira função xyz para construir coordenadas tri-dimensionais e vamos definiras funções cx, cy e cz para aceder às coordenadas x, y e z, respectiva-mente. Comecemos pela função xyz:

(defun xyz (x y z)(cons (cons x y) z))

Reparemos que a função produz o “triplo” fazendo um par com os doisprimeiros elementos x e y e, em seguida, fazendo um par com o par an-terior e com o terceiro elemento z. Em notação de “caixa e ponteiro” esteagrupamento de elementos tem a seguinte forma:

x y

z

Como é evidente, qualquer outro arranjo de pares que juntasse os trêselementos seria igualmente válido.

A partir do momento em que temos a função xyz que constrói as coor-denadas, estamos em condições de definir as funções que acedem às suascomponentes:

(defun cx (c)(car (car c)))

(defun cy (c)(cdr (car c)))

(defun cz (c)(cdr c))

Notemos que as funções que seleccionam os componentes das coorde-nadas têm de ser consistentes com os pares construídos pela função xyz.Uma vez que a coordenada x é o elemento da esquerda do par que é o ele-mento da esquerda do par que contém os componentes das coordenadas,precisamos de empregar duas vezes a função car na definição da funçãocx. Do mesmo modo, a coordenada y é o elemento da direita do par que é

46

Page 48: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

o elemento da esquerda, pelo que temos primeiro de aplicar a função carpara aceder ao par que contém x e y e temos de lhe aplicar a função cdrpara aceder a y.

As duas últimas combinações podem ser feita de forma abreviada usandoas funções pré-definidas caar e cdar:

_$ (caar (cons (cons 1 2) 3))1_$ (cdar (cons (cons 1 2) 3))2

Repare-se que a sequência de letras a e d entre as letras c e r indica acomposição de funções em questão. Assim, a função cadr significa o cardo cdr do argumento, i.e., (cadr c)=(car (cdr c)); e a função caarsignifica o car do car do argumento, i.e., (caar c)=(car (car c)).Por tradição, o Auto Lisp define todas as possíveis combinações de até qua-tro invocações das funções car e cdr. Assim, para além das funções caar,cadr, cdar e cddr que correspondem a todas as possíveis invocações deduas funções, existem ainda as variações de três invocações caaar, caadr,cadar, etc., e as variações de quatro invocações caaaar, caaadr, caadar,caaddr, etc. No entanto, deve-se evitar a utilização destas combinações defunções como cadar, cdadar, cdar e, por vezes, até mesmo as car e cdr,pois tornam o código pouco claro. Para termos um pouco mais de clarezadevemos definir funções cujo nome seja suficientemente explicativo do quea função faz.

A partir do momento em que temos coordenadas tri-dimensionais po-demos definir operações que lidem com elas. Uma função útil é a que medea distância entre dois pontos no espaço tri-dimensional. Ela corresponde auma generalização trivial da função distancia-2d onde é necessário terem conta a coordenada z dos dois pontos. Num espaço tri-dimensional, adistância d entre os pontos P0 = (x0, y0, z0) e P1 = (x1, y1, z1) é dada por

d =√

(x1 − x0)2 + (y1 − y0)2 + (z1 − z0)2

Traduzindo está definição 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))))))

À semelhança do que fizemos para as coordenadas bi-dimensionais,também podemos definir operadores para incrementar as coordenadas tri-

47

Page 49: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

dimensionais de um ponto de uma determinada “distância” especificadaem termos das projecções ∆x, ∆y e ∆z :

(defun +xyz (p dx dy dz)(xyz (+ (cx p) dx)

(+ (cy p) dy)(+ (cz p) dz)))

Tal como acontecia com a função +xy, também a função +xyz é inde-pendente do arranjo particular de pares que usemos para implementar ascoordenadas tri-dimensionais. Desde que mantenhamos a consistência en-tre as funções cx, cy e cz, que seleccionam os componentes das coordena-das tri-dimensionais, e a função xyz que cria coordenadas tri-dimensionaisa partir dos seus componentes, podemos livremente empregar outros ar-ranjos de pares.

Exercício 4.5.1 Defina a função +z que, dado um ponto em coordenadas tri-dimensionais,calcula as coordenadas do ponto que lhe está directamente por cima à distância ∆z .

Exercício 4.5.2 Defina a função ponto-medio que calcula as coordenadas tridimensionaisdo ponto médio entre dois outros pontos P0 e P1 descritos também pelas suas coordenadastridimensionais.

4.6 Coordenadas Bi- e Tri-Dimensionais

Embora tenhamos conseguido implementar quer coordenadas bi-dimensionais,quer coordenadas tri-dimensionais, as suas implementações em termos depares são intrinsecamente incompatíveis. Este problema é claramente visí-vel, por exemplo, na implementação da operação que selecciona a coorde-nada x que, na versão para coordenadas bi-dimensionais, tem a forma

(defun cx (c)(car c))

e, na versão para coordenadas tri-dimensionais, tem a forma

(defun cx (c)(car (car c)))

Obviamente, não é possível termos duas funções diferentes com o mesmonome, pelo que temos de escolher qual das versões pretendemos usar e, porarrastamento, qual o número de dimensões que pretendemos usar.

Ora, do ponto de vista matemático, as coordenadas bi-dimensionais sãoapenas um caso particular das coordenadas tri-dimensionais e, portanto,

48

Page 50: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

seria desejável podermos ter uma única operação cx capaz de obter a coor-denada x quer de coordenadas bi-dimensionais, quer de coordenadas tri-dimensionais. Logicamente, o mesmo podemos dizer da operação cy.

Para isso, é necessário repensarmos a forma como implementamos ascoordenadas em termos de pares, de modo a encontrarmos um arranjo depares que seja utilizável por ambos os tipos de coordenadas. Para simpli-ficar, podemos começar por considerar que, à semelhança do que fizemospara o caso bi-dimensional, usamos um primeiro par para conter a coorde-nada x, tal como se apresenta em seguida:

x ?

Falta agora incluirmos a coordenada y no caso bi-dimensional e as co-ordenadas y e z no caso tri-dimensional. Se o objectivo é termos um arranjode pares que funcione para os dois casos, então é crucial que a coordenaday fique armazenada de forma idêntica em ambos. Uma vez que as coorde-nadas tri-dimensionais exigem pelo menos mais um par, podemos arbitrara seguinte solução:

x

y ?

Embora no caso bi-dimensional não seja preciso armazenar mais nada,um par é sempre composto por dois elementos, pelo que temos de decidir oque guardar no lugar assinalado com “?.” Uma vez que para coordenadasbi-dimensionais não há nada para guardar nesse lugar, podemos empregarum elemento qualquer que signifique o nada, o vazio. A linguagem Lispdisponibiliza a constante nil precisamente para esse fim. O nome nil éuma contracção da palavra nihil que, em latim, significa o vazio.

Empregando a constante nil, as coordenadas bi-dimensionais (x, y)passam a ter a seguinte implementação:

49

Page 51: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

x

y nil

Para construir a estrutura anterior, a função xy passa a ter a seguintedefinição:

(defun xy (x y)(cons x (cons y nil)))

No caso das coordenadas tri-dimensionais, poderíamos substituir o “?”pelo valor da coordenada z mas, tal como considerámos as coordenadas bi-dimensionais como um caso particular das coordenadas tri-dimensionais,também as coordenadas tri-dimensionais podem ser vistas como um casoparticular das coordenadas tetra-dimensionais e assim sucessivamente.13

Isto sugere que devemos “repetir” a mesma estrutura à medida que va-mos aumentando o número de dimensões. Assim, para as coordenadastri-dimensionais (x, y, z), podemos conceber a seguinte organização:

x

y

z nil

Obviamente, precisamos de redefinir a função xyz:

(defun xyz (x y z)(cons x (cons y (cons z nil))))

É fácil constatarmos que as duas estruturas anteriores são perfeitamentecompatíveis no sentido de podermos ter uma só versão das operações cxe cy que funcione quer para coordenadas bi-dimensionais, quer para coor-denadas tri-dimensionais. De acordo com a notação de “caixa e ponteiro”apresentada, podemos definir:

13Embora, do ponto de vista da Arquitectura clássica, não seja necessário trabalhar commais do que três coordenadas, as modernas ferramentas de visualização podem necessitarde trabalhar com coordenadas tetra-dimensionais, por exemplo, para lidarem com o tempo.

50

Page 52: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(defun cx (c)(car c))

(defun cy (c)(car (cdr c)))

(defun cz (c)(car (cdr (cdr c))))

É importante referirmos que esta redefinição das funções não perturbaas funções já definidas +xy, distancia-2d e distancia-3d. De facto,desde que se mantenha a consistência entre as funções que constróiem ascoordenadas e as que seleccionam os seus componentes, nada será afec-tado.

4.7 A Notação de Lista

O arranjo de pares que adoptámos para implementar coordenadas não éoriginal, sendo usado desde a invenção da linguagem Lisp para imple-mentar agrupamentos com um número arbitrário de elementos. A essesagrupamentos dá-se o nome de listas. As listas são um tipo de dados muitoutilizado na linguagem Lisp e o nome Lisp é, na verdade, um acrónimo de“List Processing.”

De forma a tornar o uso de listas mais simples, o Lisp não só disponibi-liza um conjunto de operações especificamente destinadas a lidar com listascomo imprime as listas de forma especial: quando o segundo elemento deum par é outro par ou é nil, o Lisp escreve o resultado sob a forma de umalista de elementos:

_$ (cons 1 (cons 2 (cons 3 nil)))(1 2 3)

Repare-se, no exemplo anterior, que os pares foram escritos usandouma notação diferente que evita o ponto necessário para representar os“dotted pairs” e evita também escrever a constante nil. Esta notação é in-tencionalmente usada pelo Lisp para facilitar a leitura de listas pois, quandose pensa numa lista como uma sequência de elementos é preferível ver es-ses elementos dispostos em sequência a vê-los como um aglomerado depares. Contudo, convém não esquecermos que, internamente, a lista é defacto implementada usando um aglomerado de pares.

Dada uma lista de elementos, qual o significado de lhe aplicar as ope-rações car e cdr? Para responder a esta pergunta podemos simplesmenteexperimentar:

51

Page 53: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

_$ (car (cons 1 (cons 2 (cons 3 nil))))1_$ (cdr (cons 1 (cons 2 (cons 3 nil))))(2 3)

Note-se que a função car obteve o primeiro elemento da lista enquantoque a função cdr obteve os restantes elementos da lista, i.e., a lista a par-tir (inclusive) do segundo elemento. Isto sugere que podemos ver umalista como sendo composta por um primeiro elemento seguido do resto dalista. Segundo este raciocínio, depois de termos obtido o último elementoda lista, o resto da lista deverá ser uma lista vazia, i.e., uma lista sem quais-quer elementos. Para testarmos esta ideia podemos aplicar sucessivamentea função 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 fun-ção cdr, a lista foi “encolhendo,” i.e., fomos acedendo a partes sucessiva-mente mais pequenas da lista. No limite, quando aplicámos o cdr à lista(3) que já só tinha um elemento, estaríamos à espera de obter a lista vazia(), i.e, a lista sem quaisquer elementos mas, no seu lugar, obtivémos nil.Tal deve-se ao facto de as “listas” do Lisp serem apenas um artifício de vi-sualização sobre um arranjo particular de pares e, na realidade, a operaçãocdr continua a fazer o que sempre fez: acede ao segundo elemento do parque, no caso de uma lista com um só elemento é apenas a constante nil.Por este motivo, para além de representar o vazio, é usual considerar que aconstante nil também representa a lista vazia.

Tal como as funções car e cdr podem ser vistas como operações sobrelistas, também a função cons o pode ser. Reparemos na seguinte interac-ção:

_$ (cons 1 nil)(1)_$ (cons 1 (cons 2 nil))(1 2)_$ (cons 1 (cons 2 (cons 3 nil)))(1 2 3)

52

Page 54: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Como podemos ver, quando o segundo argumento de um cons é umalista (vazia ou não), o resultado é visto como a lista que resulta de juntar oprimeiro argumento do cons no início daquela lista.

Para simplificar a criação de listas, o Lisp disponibiliza uma função querecebe qualquer número de argumentos e que constroi uma sequência depares com os sucessivos argumentos de forma a constituirem uma lista:

_$ (list 1 2 3 4)(1 2 3 4)_$ (list 1 2)(1 2)_$ (list 1)(1)

Como é evidente, uma expressão da forma (list e1 e2 ... en) é ab-solutamente idêntica a (cons e1 (cons e2 (... (cons en nil) ...))).

Obviamente, quando recebe zero argumentos a função list produzuma lista vazia:

_$ (list)nil

Exercício 4.7.1 Qual o significado da expressão (list (list))?

Exercício 4.7.2 Quantos elementos tem a lista resultante de (list (list (list)))?

Exercício 4.7.3 Qual o significado da expressão (cons (list 1 2) (list 3 4))?

4.8 Átomos

Vimos que os pares (e as listas) permitem-nos criar aglomerações de ele-mentos e que podemos posteriormente aceder aos componentes dessas aglo-merações usando as operações car e cdr. De facto, através de combina-ções de cars e cdrs conseguimos aceder a qualquer elemento que façaparte da aglomeração.

O que não é possível, contudo, é usar car ou cdr para aceder ao inte-rior de um desses elementos. Por exemplo, não é possível, usando as ope-rações car ou cdr, aceder a um carácter qualquer dentro de uma string.Por este motivo, as strings dizem-se atómicas, i.e., não decomponíveis. Osnúmeros, obviamente, também são atómicos.

Sendo uma lista uma aglomeração de elementos, é natural pensar queuma lista não é atómica. Contudo, há uma lista em particular que merece

53

Page 55: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

um pouco mais de atenção: a lista vazia. Uma lista vazia não é decomponí-vel pois, de facto não contém nenhum elemento que se possa obter usandoo car nem nenhuns restantes elementos que se possam obter usando ocdr.14 Se não se pode usar nem o car nem o cdr, isso sugere que a listavazia é, 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 definição de atomicidade pois faz com queexista uma lista—a lista vazia—que aparenta ser simultaneamente atómicae não atómica. No entanto, o parodoxo é apenas aparente pois, na reali-dade, a definição de atomicidade apenas exclui pares. Uma vez que a listavazia não é um par, ela é atómica, embora seja uma lista.15

Exercício 4.8.1 Classifique, quanto à atomicidade, o resultado da avaliação das seguintesexpressões:

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 utilização das operações xyz, cx, cy e cz permite-nos definir um novotipo de dados—as coordenadas cartesianas tri-dimensionais—e, mais im-portante, permite-nos abstrair a implementação desse tipo de dados, i.e.,esquecer o arranjo particular de pares que o implementa. Por este motivo,denomina-se este novo tipo de dados por tipo abstracto. Ele é abstracto por-que apenas existe no nosso pensamento. Para o Lisp, como vimos, as coor-denadas são apenas arranjos particulares de pares. Esse arranjo particulardenomina-se representação dos elementos do tipo e, como vimos quando

14Na realidade, alguns dialectos de Lisp, incluindo o Auto Lisp, consideram que é possí-vel aplicar as funções car e cdr à lista vazia, obtendo-se, em ambos os casos, a lista vazia.

15Nesta matéria, a documentação do Auto Lisp está simplesmente incorrecta pois afirmaque “tudo o que não for uma lista é um átomo,” esquecendo-se de excluir a lista vazia que,obviamente, é uma lista mas é também um átomo.

54

Page 56: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

mudámos de um particular arranjo de pares para outro, é possível alterar-mos a representação de um tipo abstracto sem afectar os programas queusam o tipo abstracto.

Um tipo abstracto é caracterizado apenas pelas suas operações e estaspodem ser divididas em dois conjuntos fundamentais: os construtores que,a partir de argumentos de tipos apropriados, produzem elementos do tipoabstracto, e os selectores que, a partir de um elemento do tipo abstracto, pro-duzem os seus constituintes. Existem ainda outras categorias de operaçõesmas, por agora iremos concentrarmo-nos apenas nestas duas.

No caso das coordenadas cartesianas tri-dimensionais, o conjunto dosconstrutores apenas contém a função xyz, enquanto que o conjunto dos se-lectores contém as funções cx, cy e cz. Para um tipo abstracto, a relaçãoentre os construtores e os selectores é crucial pois eles têm de ser consisten-tes entre si. Matematicamente, essa consistência é assegurada por equaçõesque, 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 modificarmos a representação de coordenadas mas mantivermos aconsistência entre os construtores e os selectores, manter-se-á também ocorrecto funcionamento do tipo abstracto. Foi por este motivo que nos foipossível refazer a implementação das coordenadas bi- e tri-dimensionaissem afectar as funções já definidas +xy, distancia-2d e distancia-3d.

Exercício 4.9.1 O que é um construtor de um tipo abstracto?

Exercício 4.9.2 O que é um selector de um tipo abstracto?

Exercício 4.9.3 O que é a representação de um tipo abstracto?

Exercício 4.9.4 Dado um ponto P0 = (x0, y0) e uma recta definida por dois pontos P1 =(x1, y1) e P2 = (x2, y2), a distância mínima d do ponto P0 à recta obtém-se pela fórmula:

d =|(x2 − x1)(y1 − y0)− (x1 − x0)(y2 − y1)|p

(x2 − x1)2 + (y2 − y1)2

Defina uma função denominada distancia-ponto-recta que, dadas as coordenadasdos pontos P0, P1 e P2, devolve a distância mínima de P0 à recta definida por P1 e P2.

55

Page 57: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

4.10 Coordenadas em AutoCad

Como mostrámos nas secções anteriores, a compatibilização das operaçõesque lidam com coordenadas bi- e tri-dimensionais levou-nos a escolherrepresentá-las por intermédio de listas. Para além de esta representação sermais simples de ler, tem ainda outra enorme vantagem: é totalmente com-patível com a forma como as funcionalidades do AutoCad esperam recebercoordenadas. De facto, como iremos ver, o próprio AutoCad necessita queas coordenadas das entidades geométricas que pretendemos criar sejam es-pecificadas como listas de números: dois números no caso das coordenadasbi-dimensionais e três números no caso das coordenadas tri-dimensionais.

Seria então de esperar que já existissem pré-definidas em Auto Lisp asoperações que lidam com coordenadas mas, na realidade, tal não aconteceporque, na altura em que o Auto Lisp foi criado a teoria dos tipos abstractosainda não tinha sido efectivamente posta em prática. Nessa altura, nãose tinha a noção clara das vantagens desta abordagem mas tinha-se umanoção muito clara de um dos seus problemas: piorava a performance dosprogramas.

De facto, é óbvio que, a partir de uma lista representando as coordena-das de um ponto, é mais rápido obter a coordenada x usando a função cardo que usando o selector cx que, indirectamente, invoca a função car.

Como, na altura em que a teoria dos tipos abstractos apareceu, os com-putadores ainda não eram suficientemente rápidos para que os programa-dores se pudessem dar ao luxo de “desperdiçar” performance, a penalizaçãoinduzida pela teoria não foi bem aceite durante algum tempo.16 Quandoos computadores se tornaram suficientemente rápidos, a situação mudou eos programadores passaram a considerar que as vantagens da utilização detipos abstractos ultrapassava largamente a cada vez mais residual desvan-tagem da perda de performance. Actualmente, é ponto assente que devemossempre usar tipos abstractos.

Infelizmente, o Auto Lisp foi desenvolvido há demasiados anos e nãose encontra tão actualizado como seria desejável. Se fizermos uma análisedos programas Auto Lisp existentes, incluindo programas desenvolvidosrecentemente, iremos constatar que a prática usual é a manipulação di-recta da representação dos tipos, saltando por cima de qualquer definiçãode tipos abstractos. Em particular, a manipulação de coordenadas é feita

16Essa penalização variava de linguagem para linguagem. Nalgumas linguagens, ditasestaticamente tipificadas, a penalização poderia ser pequena. Noutras, ditas dinamicamentetipificadas, a penalização era geralmente mais elevada. O Lisp insere-se no grupo das lin-guagens dinamicamente tipificadas.

56

Page 58: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

usando directamente as operações do tipo lista, i.e., construindo coordena-das com a função list e acedendo aos seus valores com as funções car,cadr e caddr. Acontece que esta violação do tipo abstracto ocorre, actual-mente, muito mais por razões históricas do que por razões de performance.

Embora sejamos grandes defensores do respeito à pragmática do AutoLisp, neste caso particular vamos adoptar uma abordagem diferente: pormotivos de clareza dos programas, de facilidade da sua compreensão e defacilidade da sua correcção, vamos empregar as operações do tipo abstractocoordenadas, nomeadamente os construtores xy e xyz e os selectores cx,cy e cz e vamos evitar, sempre que possível, aceder directamente à repre-sentação das coordenadas, i.e., vamos evitar usar as funções list, car,cadr e caddr para manipular coordenadas. Isso não impede que usemosessas funções para outros fins, em particular, para manipular listas. Umavez que as coordenadas estão implementadas usando listas, esta distinçãopoderá parecer confusa mas, na verdade, não é: as coordenadas não sãolistas embora a representação das coordenadas seja uma lista.

Naturalmente, quando o leitor consultar programas escritos por outrosprogramadores de Auto Lisp deverá ter em conta estas subtilezas e deveráconseguir perceber se uma dada lista presente num programa significa co-ordenadas ou se significa outro tipo abstracto qualquer.

4.11 Coordenadas Polares

Uma das vantagens da utilização dos tipos abstractos de informação é quese torna fácil desenvolver novas operações com base nas operações do tipo.Por exemplo, embora o tipo coordenadas bi-dimensionais esteja descritoem termos de coordenadas rectangulares, nada nos impede de definir opera-ções para manipular coordenadas polares.

Tal como representado da Figura 6, uma posição no plano bi-dimensionalé descrita pelos números x e y—significando, respectivamente, a abcissae a ordenada—enquanto que a mesma posição em coordenadas polares édescrita pelos números ρ e φ—significando, respectivamente, o raio vector(também chamado módulo) e o ângulo polar (também chamado argumento).Com a ajuda da trigonometria e do teorema de Pitágoras conseguimos fa-cilmente relacionar estas coordenadas entre si:{

x = ρ cosφy = ρ sinφ

57

Page 59: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

φ

x

Figura 6: Coordenadas rectangulares e polares.

ρ =√x2 + y2

φ = arctany

x

Com base nas equações anteriores, podemos agora definir a função pol(abreviatura de “polar”) que contrói coordenadas a partir da sua represen-tação polar simplesmente convertendo-a para a representação rectangularequivalente.

(defun pol (ro fi)(xy (* ro (cos fi))

(* ro (sin fi))))

Assim sendo, o tipo abstracto coordenadas polares fica representado emtermos do tipo coordenadas rectangulares. Por este motivo, os selectoresdo tipo coordenadas polares—a função pol-ro que nos permite obter omódulo ρ e a função pol-fi que nos permite obter o argumento φ—terãode usar as operações 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 funções:17

_$ (pol (sqrt 2) (/ pi 4))(1.0 1.0)

17Note-se, nestes exemplos, que alguns valores das coordenadas não são zero comoseria expectável, mas sim valores muito próximos de zero que resultam de erros dearredondamento.

58

Page 60: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

ρ

P ′

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

_$ (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 operação bastante útil é a que, dado um ponto P = (x, y)e um “vector” com origem em P e descrito em coordenadas polares poruma distância ρ e um ângulo φ, devolve o ponto localizado na extremidadedestino do vector, tal como é visualizado na Figura 7. A trigonometriapermite-nos facilmente concluir que as coordenadas do ponto destino sãodadas por P ′ = (x+ ρ cosφ, y + ρ sinφ).

A tradução directa da função para Lisp é:

(defun +pol (p ro fi)(xy (+ (cx p) (* ro (cos fi)))

(+ (cy p) (* ro (sin fi)))))

Como exemplos de utilização, 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)

Embora a função +pol funcione perfeitamente, a sua definição não étão simples quanto poderia ser. Isso é evidente quando a comparamos coma da função +xy (que repetimos de seguida):

59

Page 61: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(defun +xy (p dx dy)(xy (+ (cx p) dx)

(+ (cy p) dy)))

É relativamente evidente que a função +pol está a fazer parte do tra-balho que já é feito pela função +xy, nomeadamente no que diz respeito àsoma das coordenadas do ponto p com as componentes que resultam daconversão de coordenadas polares para rectangulares. Assim, é possívelsimplificar a função +pol escrevendo apenas:

(defun +pol (p ro fi)(+xy p

(* ro (cos fi))(* ro (sin fi))))

Uma observacão atenta das funções +xy e +pol permite-nos constatarque elas partilham um mesmo comportamento: ambas recebem um pontoe um “vector” a somar a esse ponto para produzir um novo ponto: esse“vector” é descrito pelos parâmetros ∆x e ∆y no primeiro caso e por ρ e φno segundo.

O facto de ambas as funções partilharem um comportamento leva-nosnaturalmente a pensar na sua possível generalização, através da defini-ção de uma única função +c (abreviatura de +coordenada) que, dado umponto P0 e outro ponto P1 representando a extremidade final de um vectorcom extremidade inicial na origem, devolve o ponto que resulta de somaresse vector ao primeiro ponto, tal como está ilustrado da Figura 8. Natu-ralmente, quer o ponto P0 quer o ponto P1 podem ser especificados emqualquer sistema de coordenadas desde que seja possível relacionar essesistema com o sistema de coordenadas rectangulares.

Para definirmos esta função a abordagem mais simples será explorar aspropriedades aditivas das coordenadas rectangulares:

(defun +c (p0 p1)(xy (+ (cx p0) (cx p1))

(+ (cy p0) (cy p1))))

Uma vez que as coordenadas polares estão representadas em termosde coordenadas rectangulares, mesmo quando especificamos coordenadaspolares a operação +c continua a funcionar correctamente.

4.12 A função command

A partir do momento em que sabemos construir coordenadas passamos apoder utilizar um conjunto muito vasto de operações gráficas do Auto Lisp.

60

Page 62: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

P0φ

x

P ′

φ

x

P1

Figura 8: O deslocamento de um ponto por adição de um vector.

Existem três maneiras diferentes de se invocar essas operações gráficasmas, por agora, vamos explorar apenas a mais simples: a função command.

A função command aceita um número arbitrário de expressões que vaiavaliando e passando os valores obtidos para o AutoCad à medida que oAutoCad os vai requerendo.18 No caso de utilização mais comum, a fun-ção command recebe uma cadeia de caracteres que descreve o comandoAutoCad que se pretende executar seguido de qualquer número de argu-mentos que serão usados como os dados necessários para a execução dessecomando.

A vantagem da função command é permitir criar programas completosque criam entidades gráficas tal como um normal utilizador de AutoCad opoderia fazer de forma manual. A título de exemplo, consideremos a cri-ação de um círculo. Para se criar um círculo em AutoCad pode-se usar ocomando circle e fornecer-lhe as coordenadas do centro e o raio do cír-culo. Se pretenderemos criar o mesmo círculo a partir do Auto Lisp, aoinvés de invocarmos interactivamente o comando AutoCad circle e delhe fornecermos os dados necessários, podemos simplesmente invocar afunção command e passar-lhe todos os dados necessários como argumen-tos, começando pela string "circle", seguida das coordenadas do centrodo círculo e, por último, seguida do raio do círculo.

Para concretizarmos o exemplo, consideremos a criação de um círculode raio r = 1 centrado na posição (x, y) = (2, 3). A invocação Auto Lisp

18Este comportamento mostra que, na realidade, command não pertence ao conjunto dasfunções “normais” pois, ao contrário destas, só avalia os argumentos à medida que eles vãosendo necessários.

61

Page 63: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

que cria este círculo é a seguinte:

_$ (command "circle" (list 2 3) 1)nil

Como se pode ver pelo exemplo, as coordenadas do centro do círculoforam especificadas através da criação de uma lista. No entanto, como refe-rimos na secção 4.10, vamos evitar a especificação de coordenadas directa-mente em termos da sua representação como listas e vamos, em seu lugar,usar as operações do tipo. Assim, a expressão anterior fica mais correcta naseguinte forma:

_$ (command "circle" (xy 2 3) 1)nil

Como se pode ver também, a invocação da função command devolvenil como resultado.

Um outro exemplo da utilização desta função é na colocação de umtexto na nossa área de desenho. Para isso, podemos usar novamente a fun-ção command mas, desta vez, os argumentos a passar serão outros, nome-adamente, a cadeia de caracteres "text" que designa o comando dese-jado, as coordenadas onde pretendemos colocar o canto inferior esquerdodo texto, um número que representa a altura do texto, um número que re-presenta o ângulo (em radianos) que a base do texto deverá fazer com ahorizontal e, finalmente, uma cadeia de caracteres com o texto a inserir. Eisum exemplo:

_$ (command "text" (xy 1 1) 1 0 "AutoCad")nil

O resultado da avaliação das duas invocações anteriores é visível daFigura 9.

Finalmente, a função command pode ser usada para alterar os parâme-tros de funcionamento do AutoCad. Por exemplo, para desligar os ObjectSnaps podemos fazer:

_$ (command "osnap" "off")nil

É importante memorizar esta última expressão pois, sem a sua invoca-ção, todos os usos da função command estarão sob o efeito de Object Snaps,fazendo com que as coordenadas que indicamos para as nossas figuras ge-ométricas não sejam estritamente respeitadas pelo AutoCad, que as “arre-dondará” de acordo com a malha do Object Snaps.

62

Page 64: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 9: Um círculo com o texto "AutoCad".

Como exemplo da utilização de comandos em Auto Lisp, a Figura 10mostra o resultado da avaliação das seguintes expressões onde usamos co-ordenadas polares para desenhar círculos 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")

Exercício 4.12.1 Refaça o desenho apresentado na Figura 10 mas utilizando apenas coor-denadas rectangulares.

Exercício 4.12.2 Defina uma função denominada circulo-e-raio que, dadas as coorde-nadas do centro do círculo e o raio desse círculo, cria o círculo especificado no AutoCad e, àsemelhança do que se vê na Figura 10, coloca o texto a descrever o raio do círculo à direitado círculo. O texto deverá ter um tamanho proporcional ao raio do círculo.

Exercício 4.12.3 Utilize a função circulo-e-raio definida na pergunta anterior para re-constituir a imagem apresentada na Figura 10.

Existem algumas particularidades do comportamento da função commandque é importante discutir. Para as compreendermos é preciso recordar quea função command “simula” a interacção do utilizador com o AutoCad.Consideremos então um exemplo de uma interacção: imaginemos que es-tamos em frente à interface do AutoCad e pretendemos apagar todo o con-teúdo da nossa área de desenho no AutoCad. Para isso, podemos invocar

63

Page 65: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 10: Círculos e textos especificados usando coordenadas polares.

o comando erase do AutoCad, o que podemos fazer escrevendo as le-tras e-r-a-s-e e premindo enter no final. Acontece que o comando nãopode ser imediatamente executado pois o AutoCad precisa de saber maisinformação, em particular, o que é que é para apagar. Para isso, o Auto-Cad pede-nos para seleccionar um ou mais objectos para apagar. Nessaaltura, se respondermos com a palavra all e premirmos novamente a te-cla enter, o AutoCad selecciona todos os objectos mas fica a aguardar queindiquemos que terminámos a selecção de objectos, o que se pode fazerpremindo simplesmente a tecla enter.

Ora para que a função command possa simular a interacção que aca-bámos de descrever, ela tem de passar ao AutoCad todas as informaçõesnecessárias e tem de o fazer à medida que o AutoCad precisa delas. As-sim, cada sequência de teclas que foi por nós dada ao AutoCad deverá seragora dada na forma de string como argumento à função command. No en-tanto, como não faz muito sentido obrigar o utilizador a especificar, numastring o premir da tecla enter, a função command assume que, após passartodos os caracteres de uma string ao AutoCad, deve passar-lhe também ocorrespondente “premir da tecla enter.”

Tentemos agora, à luz desta explicação, construir a invocação da funçãocommand que simula a interacção anterior. O primeiro passo da avaliaçãoda expressão é, como referimos, o passar da sequência de letras e-r-a-s-eseguidas do premir virtual da tecla enter, o que podemos fazer escre-vendo:

64

Page 66: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(command "erase" ...)

Em seguida, sabemos que o AutoCad nos vai pedir para seleccionarmosos objectos a apagar, pelo que escrevemos a string com a palavra all quea função irá passar ao AutoCad, novamente terminando-a com o premirvirtual da tecla enter:

(command "erase" "all" ...)

Finalmente, sabemos que depois desta interacção, o AutoCad vai conti-nuar à espera que indiquemos que terminámos a selecção de objectos atra-vés do premir da tecla enter, o que implica que temos de indicar à funçãocommand para simplesmente passar o tal “premir virtual da tecla enter.”Ora já sabemos que a função faz isso automaticamente após passar os ca-racteres de uma string pelo que, se não queremos passar caracteres algunsmas apenas a tecla enter então, logicamente, temos de usar uma stringvazia, ou seja:

(command "erase" "all" "")

Assim, a string vazia, quando usada como argumento de command, éequivalente a premir a tecla enter na linha de comandos do AutoCad.

É claro que, se na sequência de uma invocação da função command, oAutoCad ficar à espera de dados, novas invocações da função command po-derão providenciar esses dados ou o utilizador poderá dar essa informaçãodirectamente no AutoCad. Isto quer dizer que a invocação anterior podetambém ser feita na forma:

(command "erase")(command "all")(command "")

Como se pode constatar pelo exemplo anterior, a função command ter-mina assim que conseguir passar todos os argumentos que tem para o Au-toCad, independentemente de eles serem suficientes ou não para o Auto-Cad conseguir completar o pretendido. Se não forem, o AutoCad limita-sea continuar à espera que lhe forneçamos, via command ou directamente nainterface, os dados que lhe faltam, o que nos permite implementar um pro-cesso de “colaboração” com o AutoCad: parte do que se pretende é feito nolado do Auto Lisp e a parte restante no lado do AutoCad.

Por exemplo, imaginemos que pretendemos criar um círculo num dadoponto mas queremos deixar ao utilizador a escolha do raio. Uma solução

65

Page 67: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

será iniciar a construção do círculo centrado num dado ponto através dafunção command mas aguardar que o utilizador termine essa construçãoindicando explicitamente no AutoCad (por exemplo, usando o rato) qual éo raio do círculo pretendido. Assim, iniciariamos o comando com:

(command "circle" (xy 0 0))

e o utilizador iria então ao AutoCad terminar a criação do círculo atravésda indicação do raio.

Um problema um pouco mais complicado será criar um círculo de raiofixo mas deixar ao utilizador a escolha do centro. A complicação deriva denão conhecermos as coordenadas do centro mas querermos passar o raio:se nos falta o argumento do “meio,” ou seja, a posição do centro do círculo,não podemos passar o do “fim,” ou seja, o raio do círculo.

Há várias soluções para este problema mas, por agora iremos explorarapenas uma. Para contornar o problema, o AutoCad permite a utilizaçãodo carácter especial “\” para indicar que se pretende suspender momenta-neamente a passagem de argumentos para o AutoCad, para se retomar essapassagem assim que o AutoCad obtenha o valor correspondente ao argu-mento que não foi passado. Para facilitar a legibilidade dos programas, osímbolo pause designa precisamente a string que contém esse único carác-ter. A seguinte interacção mostra um exemplo da utilização deste símbolopara resolver o problema da criação de um círculo de raio igual a 3 mascentro especificado pelo utilizador. Note-se que, tal como referido na Ta-bela 1, o carácter “\” é um carácter de escape e é por isso que tem de serescrito em duplicado.

_$ pause"\\"_$ (command "circle" pause 3)nil

Um outro aspecto importante da função command prende-se com a pas-sagem de números e coordenadas (representadas por listas de números).Embora nos exemplos anteriores estes tipos de dados tenham sido directa-mente passadas à função command, na realidade também podem ser passa-dos “simulando” o premir das teclas correspondentes. Isto quer dizer queé possível criar um círculo com centro no ponto (2, 3) e raio 1 através daexpressão:

(command "circle" "2,3" "1")

66

Page 68: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

O que acontece, na prática, é que os argumentos da função command,para além de só serem avaliados quando são necessários, são também au-tomaticamente convertidos para o formato pretendido pelo AutoCad. Istopermite-nos “trabalhar” as propriedades das entidades geométricas no for-mato que nos é mais conveniente (números, coordenadas, etc) e deixar àfunção command a responsabilidade de converter os valores para o formatoapropriado para o AutoCad.

Exercício 4.12.4 Pretendemos colocar duas circunferências de raio unitário em torno daorigem de modo a que fiquem encostadas uma à outra, tal como se ilustra no seguintedesenho:

Escreva uma sequência de expressões que, quando avaliadas, produzem a figura ante-rior.

Exercício 4.12.5 Pretendemos colocar quatro circunferências de raio unitário em torno daorigem de modo a que fiquem encostadas umas às outras, tal como se ilustra no seguintedesenho:

Escreva uma sequência de expressões que, quando avaliadas, produzem a figura ante-rior.

Exercício 4.12.6 Pretendemos colocar três circunferências de raio unitário em torno da ori-gem de modo a que fiquem encostadas umas às outras, tal como se ilustra no seguintedesenho:

Escreva uma sequência de expressões que, quando avaliadas, produzem a figura ante-rior.

67

Page 69: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

4.13 Variantes de Comandos

Quando fornecemos um nome na linha de comando do AutoCad, ele tentaperceber o que é pedido seguindo um algoritmo que involve os seguintespassos:19

1. O nome é pesquisado na lista de comandos do AutoCad. Se o nomeestá na lista, então, se o nome é precedido de um ponto “.,” executao comando e termina, caso contrário pesquisa o nome na lista de co-mandos não-definidos20 e, se não o encontrar, executa o comando etermina.21

2. O nome é pesquisado na lista de comandos externos definidos no fi-cheiro de parâmetros acad.pgp. Se o encontrar, executa o comandoe termina.

3. O nome é pesquisado na lista de comandos definidos pelo Auto Lisp.Se o encontrar então, primeiro, verifica se é um comando de carrega-mento automático e, se for, o programa correspondente é carregadoe, segundo, executa o comando e termina.

4. O nome é pesquisado na lista de sinónimos (aliases) definidos no fi-cheiro de parâmetros do programa. Se o encontrar, substitui o nomepela sua expansão e volta ao princípio.

5. Termina com uma mensagem de erro indicando que o nome é desco-nhecido.

Repare-se que o algoritmo anterior fala de comandos cujo nome é pre-cedido de um ponto, de comandos não definidos, comandos externos, etc.Todas estas variedades existem porque, na realidade, é possível redefinirou tornar como não definidos os comandos pré-definidos do AutoCad. Istoimplica que quando invocamos um comando como, por exemplo, circle,estamos na realidade a invocar a mais recente definição que foi feita paraesse comando. Só no caso de não ter sido feita qualquer redefinição do co-mando e de este não ter sido tornado não definido é que iremos invocar

19Por motivos pedagógicos, esta descrição é uma simplificação da realidade.20Um comando não-definido não é a mesma coisa que um comando indefinido. O primeiro

corresponde a um comando conhecido que foi explicitamente declarado como não definidoenquanto o segundo corresponde a um comando totalmente desconhecido.

21Este comportamento permite que se possam tornar comandos como não-definidos e,ainda assim, pode executá-los desde que se preceda o seu nome de um ponto.

68

Page 70: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

a definição original. A consequência é que, não sabendo se foi feita umaredefinição ou se o comando não foi tornado como não definido, não pode-mos ter a certeza do que vai realmente ser executado.

Como se pode ver pelo algoritmo descrito acima, o AutoCad admiteuma variante para todos os comandos: se o nome do comando começarcom o carácter ponto “.” então é feita a execução do comando pré-definidodo AutoCad. Desta forma, este pequeno “truque” permite-nos ultrapassarqualquer redefinição ou não definição de um comando.

Uma outra característica do AutoCad que pode complicar a utilizaçãoda função command é a internacionalização: em diferentes países, o Auto-Cad utiliza os nomes dos comandos traduzidos para diferentes línguas.Por exemplo, o comando circle escreve-se kreis no AutoCad Alemão,cercle no Francês, cerchio no Italiano, kružnice no Checo e circulono Espanhol. Assim, se tivermos feito um programa que invoca o comandocircle e tentarmos executar esse comando num AutoCad preparado paraoutra língua, iremos obter um erro por o comando ser desconhecido nessalíngua.

Para evitar este problema, o AutoCad admite ainda outra variante paratodos os comandos: se o nome do comando começar com o carácter “_”então é feita a execução do comando na língua original do AutoCad, que éo Inglês.

A combinação destas duas variantes é possível. O nome _.circle (ou._circle) indica a versão original do comando, independentemente dealterações linguísticas ou redefinições do comando.

Para evitar problemas, de agora em diante iremos sempre utilizar estaconvenção de preceder com os caracteres “_.” todos os comandos queusarmos na operação command.

Exercício 4.13.1 Redefina e teste a função circulo-e-raio de modo a usar os comandospré-definidos do AutoCad, independentemente de redefinições de comandos ou mudançasde língua.

Exercício 4.13.2 Defina a função comando-pre-definido que, dado o nome de um co-mando em inglês, devolve esse nome convenientemente modificado para permitir acederao comando correspondente pré-definido no AutoCad independentemente da língua emque este esteja.

4.14 Ângulos em Comandos

Alguns dos comandos do AutoCad necessitam de saber raios e ângulosem simultâneo. Por exemplo, para criar um polígono regular, o comando

69

Page 71: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

polygon necessita de saber quantos lados ele deverá ter, qual o centro dopolígono, se ele vai estar inscrito numa circunferência ou circunscrito numacircunferência e, finalmente o raio dessa circunferência e o ângulo que o“primeiro” vértice do polígono faz com o eixo dos x. Este dois últimosparâmetros, contudo, não podem ser fornecidos separadamente, sendo ne-cessário especificá-los de uma forma conjunta, através de uma string emque se junta o raio e o ângulo separados pelo carácter “<” (representandoum ângulo) e precedidos do carácter “@” (representando um incrementorelativamente ao último ponto dado, que era o centro da circunferência).Por exemplo, o raio 2 com um ângulo de 30oescreve-se "@2<30". Note-seque o ângulo tem de estar em graus. Se, ao invés de fornecermos esta stringfornecermos apenas um número, o AutoCad irá tratar esse número como oraio e, mesmo que lhe tentemos fornecer outro número para o ângulo, iráassumir que o ângulo é zero.

Uma vez que, na maior parte dos casos, os raios e ângulos serão pa-râmetros das nossas funções e ainda que, do ponto de vista matemático,é preferível trabalhar em radianos, é conveniente definir uma função que,a partir do raio e ângulo em radianos, produz a string apropriada com oângulo em graus. Para isso, é conveniente usarmos a função strcat paraconcatenarmos as strings parciais que serão produzidas através da funçãortos que converte um número numa string. Assim, temos:

(defun raio&angulo (raio angulo)(strcat "@"

(rtos raio)"<"(rtos (graus<-radianos angulo))))

Usando esta função é agora trivial criarmos polígonos com diferentesângulos de rotação. Por exemplo, a seguinte sequência de comandos pro-duz 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)))

70

Page 72: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 11: Triângulos, quadrados e pentágonos sobrepostos com diferentesângulos de rotação.

4.15 Efeitos Secundários

Vimos anteriormente que qualquer expressão Lisp tem um valor. No en-tanto, aquilo que se pretende de uma expressão que use a função commandnão é saber qual o seu valor mas sim qual o efeito que é produzido numdeterminado desenho. De facto, a execução de um comando AutoCad pro-duz, em geral, uma alteração do desenho actual, sendo irrelevante o seuvalor.

Este comportamento da função command é fundamentalmente diferentedo comportamento das funções que vimos até agora pois, anteriormente,as funções eram usadas para computar algo, i.e., para produzir um valora partir da sua invocação com determinados argumentos e, agora, não é ovalor que resulta da invocação do comando que interessa mas sim o efeitosecundário (também chamado efeito colateral) que interessa.

Contudo, mesmo no caso em que apenas nos interessa o efeito secun-dário, é necessário continuar a respeitar a regra de que, em Lisp, qualquerexpressão tem um valor e, por isso, também uma invocação de funçãotem de produzir um valor como resultado. É por este motivo que a in-vocação da função command devolve sempre nil como resultado. Obvi-amente que qualquer outro valor serviria (pois não é suposto ser usado)mas convenciona-se que nos casos em que não há um valor mais relevantea devolver deve-se devolver nil (que, em Latim, significa nada).22

22Em tutoriais de Auto Lisp aparece por vezes a sugestão de terminar a definição defunções que apenas realizam efeitos secundários com a expressão de escrita (princ). Defacto, quando invocada desta forma, a função princ não só não escreve nada como aparentanão devolver nada:

_$ (princ)_$

No entanto, na realidade, a expressão anterior devolveu, de facto, um valor: um símbolocuja representação externa não é escrita no terceiro passo do ciclo read-eval-print. Embora

71

Page 73: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Um dos aspectos importantes da utilização de efeitos secundários estána possibilidade da sua composição. A composição de efeitos secundáriosfaz-se através da sua sequenciação, i.e., da realização sequencial dos váriosefeitos. Na secção seguinte iremos ver um exemplo da composição de efei-tos secundários.

Exercício 4.15.1 Considere a seguinte interacção com o AutoCad para a criação de umtronco de cone onde apresentamos a negrito os dados fornecidos pelo utilizador:

Command: coneSpecify center point of base or [3P/2P/Ttr/Elliptical]: 1,1,1Specify base radius or [Diameter] <5.0000>: 3Specify height or [2Point/Axis endpoint/Top radius] <10.0000>: TopSpecify top radius <0.0000>: 2Specify height or [2Point/Axis endpoint] <10.0000>: 4

Tendo em conta a interacção anterior, defina uma função Auto Lisp denominada tronco-conecujos parâmetros são o ponto P do centro da base do sólido, a altura h do sólido e os raiosrb e rt da base e do topo do sólido e que cria o tronco de cone correspondente em AutoCad.

4.16 A Ordem Dórica

Na Figura 12 apresentamos uma imagem do templo grego de Segesta. Estetemplo, que nunca chegou a ser acabado, foi construído no século quintoantes de Cristo e representa um excelente exemplo da Ordem Dórica, a maisantiga das três ordens da arquitectura Grega clássica. Nesta ordem, umacoluna caracteriza-se por ter um fuste, um coxim e um ábaco. O ábacotem a forma de uma placa quadrada que assenta sobre o coxim, o coximassemelha-se a um tronco de cone invertido e assenta sobre o fuste, e o fusteassemelha-se a um tronco de cone com vinte caneluras em seu redor. Estascaneluras assemelham-se a uns canais semi-circulares escavados ao longoda coluna.23 Quando os Romanos copiaram a Ordem Dórica introduziram-lhe um conjunto de alterações, em particular, nas caneluras que, muitasvezes, são simplesmente eliminadas.

invisível, este símbolo especial não deixa de ser um valor e pode ser usado como qualqueroutro valor, embora a sua “invisibilidade” possa provocar resultados possivelmente menosexpectáveis, como a seguinte comparação mostra:

_$ (cons 1 2)(1 . 2)_$ (cons (princ) (princ))( . )

23Estas colunas apresentam ainda uma deformação intencional denominada entasis. Aentasis consiste em dar uma ligeira curvatura à coluna e, segundo alguns autores, destina-se a corrigir uma ilusão de óptica que faz as colunas direitas parecerem encurvadas.

72

Page 74: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 12: O Templo Grego de Segesta, exemplificando alguns aspectos daOrdem Dórica. Este templo nunca chegou a ser terminado, sendo visível,por exemplo, a falta das caneluras nas colunas. Fotografia de Enzo De Mar-tino.

73

Page 75: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(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 Dórica de referência.

Nesta secção vamos esquematizar o desenho de uma coluna Dórica(sem caneluras). Do mesmo modo que uma coluna Dórica se pode de-compor nos seus componentes fundamentais—o fuste, o coxim e o ábaco—também o desenho da coluna se poderá decompor no desenho dos seuscomponentes. Assim, vamos definir funções para desenhar o fuste, o coxime o ábaco. A Figura 13 apresenta um modelo de referência. Comecemos pordefinir uma função para o desenho do fuste:

(defun fuste ()(command "_.line"

(xy -0.8 10)(xy -1 0)(xy 1 0)(xy 0.8 10)(xy -0.8 10)""))

Neste exemplo, a função command executa o comando AutoCad lineque, dada uma sequência de pontos, constrói uma linha poligonal com vér-tices nesses pontos. Para se indicar o fim da sequência de pontos usa-seuma string vazia. Naturalmente, a invocação da função fuste terá, comoefeito secundário, a criação do fuste da coluna na área de desenho do Au-toCad. Uma outra possibilidade, eventualmente mais correcta, seria pedirao AutoCad a criação de uma linha fechada, algo que podemos fazer com a

74

Page 76: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

opção "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 criação de um conjuntode segmentos de recta. Cada um destes segmentos de recta é uma entidadeindividual que pode ser seleccionada e modificada independentemente dosrestantes. Para o caso de não pretendermos esse tratamento independente,o AutoCad disponibiliza polilinhas (também conhecidas por plines). Estassão criadas pelo comando pline que, neste contexto, difere do comandoline no facto de ter como resultado a criação de uma única entidade com-posta pelos vários segmentos.24

Para completar a figura, é ainda necessário definir uma função para ocoxim e outra para o ábaco. No caso do coxim, o raciocínio é 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 idêntica ou po-demos explorar outro comando do AutoCad ainda mais simples destinadoà construção de rectângulos. Este comando apenas necessita de dois pontospara definir completamente o rectângulo:

(defun abaco ()(command "_.rectangle"

(xy -1 10.5)(xy 1 11)))

Finalmente, vamos definir uma função que desenha as três partes dacoluna:

24Outras diferenças incluem o facto de as plines poderem ter espessura e estarem limita-das a um plano.

75

Page 77: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 14: Uma coluna dórica desenhada pelo AutoCad.

(defun coluna ()(fuste)(coxim)(abaco))

Repare-se, na função coluna, que ela invoca sequencialmente as fun-ções fuste, coxim e, finalmente, abaco. Para percebermos o funciona-mento da função coluna é importante saber que quando invocamos umafunção que possui uma sequência de expressões, o Lisp avalia sequenci-almente cada uma das expressões, descartando o seu valor, até chegar àúltima cujo valor é usado como valor final da função. O facto de se descar-tarem todos os valores excepto o último mostra que, numa sequenciaçãode expressões, o que importa é o efeito secundário da sua avaliação. Asequenciação é o exemplo mais simples de uma estrutura de controle. Emtermos muito grosseiros, uma estrutura de controle é um mecanismo daslinguagens de programação que indica ao computador a ordem pela qualpretendemos que ele execute o programa.

A Figura 14 mostra o resultado da invocação da função coluna.

4.17 Parameterização de Figuras Geométricas

Infelizmente, a coluna que criámos na secção anterior tem todas as suasdimensões fixas, pelo que será difícil encontrarmos outras situações em quepossamos reutilizar a função que definimos. Naturalmente, esta funçãoseria mais útil se a criação da coluna fosse parameterizável, i.e., se a criação

76

Page 78: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

rt

rb

a

P = (x, y)

P4 = (x− rb, y)

P1 = (x− rt, y + a) P2 = (x+ rt, y + a)

P3 = (x+ rb, y)

Figura 15: Esquema do desenho do fuste de uma coluna.

dependesse dos vários parâmetros que caracterizam a coluna como, porexemplo, as coordenadas da base da coluna, a altura do fuste, do coxim edo ábaco, os raios da base e do topo do fuste, etc.

Para se compreender a parameterização destas funções vamos começarpor considerar o fuste representado esquematicamente na Figura 15.

O primeiro passo para parameterizarmos um desenho geométrico con-siste na identificação dos parâmetros relevantes. No caso do fuste, um dosparâmetros óbvios é a localização espacial desse fuste, i.e., as coordenadasde um ponto de referência em relação ao qual fazemos o desenho do fuste.Assim, comecemos por imaginar que o fuste irá ser colocado com o centroda base num imaginário ponto P de coordenadas arbitrárias (x, y). Paraalém deste parâmetro, temos ainda de conhecer a altura do fuste a e osraios da base rb e do topo rt do fuste.

Para mais facilmente idealizarmos um processo de desenho, é conveni-ente assinalarmos no esquema alguns pontos de referência adicionais. Nocaso do fuste, uma vez que o seu desenho é, essencialmente, um trapézio,basta-nos idealizar o desenho deste trapézio através de uma sucessão delinhas rectas dispostas ao longo de uma sequência de pontos P1, P2, P3 e

77

Page 79: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

rb

rt

aP = (x, y)

P1 = (x− rb, y)

P2 = (x− rt, y + a) P3 = (x+ rt, y + a)

P4 = (x+ rb, y)

Figura 16: Esquema do desenho do coxim de uma coluna.

P4, pontos esses que conseguimos calcular facilmente a partir do ponto P .Desta forma, estamos em condições de definir a função que desenha

o fuste. Para tornar mais claro o programa, vamos empregar os nomesa-fuste, r-base e r-topo para caracterizar a altura a, o raio da base rbe o raio do topo rt, respectivamente. A definição fica então:

(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"))

Em seguida, temos de especificar o desenho do coxim. Mais uma vez,convém pensarmos num esquema geométrico, tal como apresentamos naFigura 16.

Tal como no caso do fuste, a partir de um ponto P correspondente aocentro da base do coxim, podemos computar as coordenadas dos pontosque estão nas extremidades dos segmentos de recta que delimitam o de-senho do coxim. Usando estes pontos, a definição da função fica com aseguinte 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 definir o desenho do ábaco. Paraisso, fazemos um novo esquema que apresentamos na Figura 17.

78

Page 80: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

l

aP = (x, y)

P1 = (x− l2 , y)

P2 = (x+ l2 , y + a)

Figura 17: Esquema do desenho do ábaco de uma coluna.

Mais uma vez, vamos considerar como ponto de partida o ponto P nocentro da base do ábaco. A partir deste ponto, podemos facilmente calcu-lar os pontos P1 e P2 que constituem os dois extremos do rectângulo querepresenta o alçado 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 osdesenhos do fuste, do coxim e do ábaco. Apenas precisamos de ter emconta que, tal como a Figura 18 demonstra, o raio do topo do fuste coincidecoincide com o raio da base do coxim e o raio do topo do coxim é metadeda largura do ábaco. A mesma Figura mostra também que as coordenadasda base do coxim correspondem a somar a altura do fuste às coordenadasda base do fuste e as coordenadas da base do ábaco correspondem a somara altura do fuste e a altura do coxim às coordenadas da base do fuste.

Tal como fizemos anteriormente, vamos dar nomes mais claros aos pa-râ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, respectiva-mente, P , af , rbf , ac, rbc, aa e la, temos:

(defun coluna (pa-fuste r-base-fustea-coxim r-base-coxima-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 funções, podemos agora facilmente experimentar va-riações de colunas. As seguintes invocações produzem o desenho apresen-tado na Figura 19.

79

Page 81: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

af

ac

aa

la

rbf

rbc

P

Figura 18: A composição do fuste, coxim e ábaco.

80

Page 82: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 19: Variações de colunas dóricas.

(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)

Como é óbvio pela análise desta figura, nem todas as colunas desenha-das obedecem aos cânones da ordem Dórica. Mais à frente iremos ver quemodificações serão necessárias para evitar este problema.

4.18 Documentação

Na função coluna, a-fuste é a altura do fuste, r-base-fuste é o raioda base do fuste, r-topo-fuste é o raio do topo do fuste, a-coxim é aaltura do coxim, a-abaco é a altura do ábaco e, finalmente, r-abaco éo raio do ábaco. Uma vez que a função já tem vários parâmetros e o seusignificado poderá não ser óbvio para quem lê a definição da função pelaprimeira vez, é conveniente documentar a função. Para isso, a linguagemLisp providencia uma sintaxe especial: sempre que surge o carácter ;, aprocesso de leitura do Lisp ignora tudo o que vem a seguir até ao fim dalinha. Isto permite-nos escrever texto nos nossos programas sem correr orisco de o Lisp tentar perceber o que lá está escrito.

Usando documentação, o nosso programa completo para desenhar co-

81

Page 83: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

lunas dóricas fica com o seguinte aspecto:25

;;;;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.(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

25O exemplo destina-se a mostrar as diferentes formas de documentação usadas em Lispe não a mostrar um exemplo típico de programa documentado. Na verdade, o programa étão simples que não deveria necessitar de tanta documentação.

82

Page 84: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

a-fuste r-base-fustea-coxim r-base-coxima-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, quem for ler o nosso programa fica com uma ideia muitomais clara do que cada função faz, sem sequer precisar de ir estudar o corpodas funções. Como se vê pelo exemplo anterior, é pragmática usual emLisp usar um diferente número de caracteres “;” para indicar a relevânciado comentário:

;;;; Devem começar na margem esquerda e servem para dividir o pro-grama em secções e dar um título a cada secção.

;;; Devem começar na margem esquerda e servem para fazer comentá-rios gerais ao programa que aparece em seguida. Não se devem usarno interior das funções.

;; Devem estar alinhadas com a parte do programa a que se vão aplicar,que aparece imediatemente em baixo.

; Devem aparecer alinhados numa mesma coluna à direita e comentam aparte do programa imediatamente à esquerda.

É importante que nos habituemos a documentar as nossas definiçõesmas convém salientar que a documentação em excesso também tem des-vantagens:

• O código Lisp deve ser suficientemente claro para que um ser hu-mano o consiga perceber. É sempre preferível perder mais tempo atornar o código claro do que a escrever documentação que o expli-que.

• Documentação que não está de acordo com o programa é pior quenão ter documentação.

• É frequente termos de modificar os nossos programas para os adaptara novos fins. Quanto mais documentação existir, mais documentaçãoé necessário alterar para a pôr de acordo com as alterações que tiver-mos feito ao programa.

83

Page 85: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Por estes motivos, devemos esforçar-nos por escrever o código maisclaro que nos for possível e, ao mesmo tempo, providenciar documenta-ção sucinta e útil: a documentação não deve dizer aquilo que é óbvio apartir da leitura do programa.

Exercício 4.18.1 Considere o desenho de uma seta com origem no ponto P , comprimentoρ, inclinação α, ângulo de abertura β e comprimento da “farpa” σ, tal como se representaem seguida:

αP

ρ σβ

Defina uma função denominada seta que, a partir dos parâmetros P , ρ, α, σ e β,constrói a seta correspondente.

Exercício 4.18.2 Com base na solução do exercício anterior, defina uma função que, dadoso ponto P , a distância ρ e o ângulo α, desenha “o norte” tal como se apresenta no esquemaem baixo:

N

O desenho deve ainda obedecer às seguintes proporções:• O ângulo β de abertura da seta é de 45 ◦.• O comprimento σ da “farpa” é de ρ

2.

• O centro da letra “N” deverá ser posicionado a uma distância de ρ10

da extremidadeda seta segundo a direcção da seta.

• O tamanho da letra “N” deverá ser metade da distância ρ.

Exercício 4.18.3 Usando a função seta, defina uma nova função denominada seta-de-paraque, dados dois pontos, cria uma seta que vai do primeiro para o segundo ponto. As farpasda seta deverão ter comprimento unitário e ângulo π

8.

Exercício 4.18.4 Considere o desenho de uma habitação composta apenas por divisões rec-tangulares. Pretende-se que defina a função divisao-rectangular que recebe comoparâmetros a posição do canto inferior esquerdo da divisão, o comprimento e a largura dadivisão e um texto a descrever a função dessa divisão na habitação. Com esses valores afunção deverá construir o rectângulo correspondente e deve colocar no interior desse rec-tângulo duas linhas de texto, a primeira com a função da divisão e a segunda com a área dadivisão. Por exemplo, a sequência de invocações

84

Page 86: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(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 habitação que se apresenta de seguida:

4.19 Depuração

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 não se passa comas linguagens de programação. Qualquer erro num programa tem, comoconsequência, que o programa tem um comportamento diferente daqueleque era esperado.

Uma vez que é fácil cometer erros, deve também ser fácil detectá-lose corrigi-los. À actividade de detecção e correcção de erros denomina-sedepuração. Diferentes linguagens de programação providenciam diferen-tes mecanismos para essa actividade. Neste domínio, como iremos ver, oAutoCad está particularmente bem apetrechado.

Em termos gerais, os erros num programa podem classificar-se em errossintáticos e erros semânticos.

4.19.1 Erros Sintáticos

Os erros sintáticos ocorrem quando escrevemos frases que não obedecem àgramática da linguagem. Como exemplo prático, imaginemos que preten-diamos definir uma função que criava um única coluna dórica, que iremos

85

Page 87: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

designar de coluna standard e que tem sempre as mesmas dimensões, nãonecessitando de quaisquer outros parâmetros. Uma possibilidade para adefinição desta função será:

(defun coluna-standard(coluna (xy 0 0) 9 0.5 0.4 0.3 0.3 0.5))

No entanto, se avaliarmos aquela definição, o Auto Lisp irá apresentarum erro, avisando-nos de que algo está errado:26

; 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 quelhe demos para avaliar não obedece à sintaxe exigida para essa forma e, defacto, uma observação atenta da forma anterior mostra que não seguimos asintaxe exigida para uma definição e que, tal como discutimos na secção 3.6,era a seguinte:

(defun nome (parâmetro1 ... parâmetron)corpo)

O nosso erro é agora óbvio: esquecemo-nos da lista de parâmetros. Se afunção não tem parâmetros a lista de parâmetros é vazia mas tem de estarlá na mesma. Uma vez que não estava, o Auto Lisp detecta e reporta umerro sintático, uma “frase” que não obedece à sintaxe da linguagem.

Há vários outros tipos de erros sintáticos que o Auto Lisp é capaz dedetectar e que serão apresentados à medida que os formos discutindo. Oimportante, no entanto, não é saber quais são os erros sintáticos detectáveispelo Auto Lisp, mas antes saber que o Auto Lisp é capaz de verificar as ex-pressões que escrevemos e fazer a detecção de erros sintáticos antes mesmode as avaliar.

Para isso, o Visual Lisp disponibiliza na sua interface operações quefazem essa verificação para uma selecção ou para todo o ficheiro actual.Na versão Inglesa do AutoCad, essas operações denominam-se “Check Se-lection” ou “Check Text in Editor” e estão disponíveis no menu “Tools.”Como consequência da invocação destas operações, o AutoCad analiza aselecção ou o ficheiro actual e escreve, numa janela à parte, todos os errossintáticos encontrados. Nesse janela, se clicarmos duas vezes sobre umamensagem de erro, somos conduzidos ao local do nosso programa onde oerro ocorre.

26Nem todos os dialectos e interpretadores de Lisp possuem exactamente este comporta-mento mas, variações à parte, os conceitos são os mesmos.

86

Page 88: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

4.19.2 Erros Semânticos

Os erros semânticos são muito diferentes dos sintáticos. Um erro semân-tico não é um erro na escrita de uma “frase” da linguagem mas sim umerro no significado dessa frase. Dito de outra forma, um erro semânticoocorre quando escrevemos uma frase que julgamos ter um significado e, naverdade, ela tem outro.

Em geral, os erros semânticos apenas são detectáveis durante a invo-cação das funções que os contêm. Parte dos erros semânticos é detectávelpelo avaliador de Lisp mas há inúmeros erros cuja detecção só pode serfeita pelo próprio programador.

Como exemplo de erro semântico consideremos uma operação sem sig-nificado como seja a soma de um número com uma string:

_$ (+ 1 "dois"); error: bad argument type: numberp: "dois"

Como se pode ver, o erro é explicado na mensagem que indica que osegundo argumento devia ser um número. Neste exemplo, o erro é sufici-entemente óbvio para o conseguirmos detectar imediatamente. No entanto,no caso de programas mais complexos, isso já poderá não ser assim.

Na continuação do exemplo que apresentámos na discussão sobre errossintáticos, consideremos a seguinte modificação à função coluna-standardque corrige a falta de parâmetros mas que introduz um outro erro:27

(defun coluna-standard ()(coluna (xy O 0) 9 0.5 0.4 0.3 0.3 0.5))

Do ponto de vista sintático, a função está correcta. No entanto, quandoa invocamos surge um erro:

_$ (coluna-standard); error: bad argument type: numberp: nil

Como podemos ver pela resposta, o Auto Lisp protesta que um dos ar-gumentos devia ser um número mas, em lugar disso, era nil. Uma vezque a função coluna-standard não tem quaisquer argumentos, a men-sagem de erro poderá ser difícil de compreender. No entanto, ela torna-secompreensível quando pensamos que o erro poderá não ter ocorrido na in-vocação da função coluna-standard mas sim em qualquer função quetenha sido invocada directa ou indirectamente por esta.

27Consegue detectá-lo?

87

Page 89: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Para se perceber melhor onde está o erro, o Visual Lisp providenciaalgumas operações extremamente úteis. Uma delas dá pelo nome de “ErrorTrace,” está disponível no menu “View” e destina-se a mostra a “cascata”de invocações que acabou por provocar o erro.28 Quando executamos essaoperação, o Visual Lisp apresenta-nos, numa pequena janela, a seguinteinformação:

<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 informação acima, as reticências representam outras invocações quenão são relevantes para o nosso problema e que correspondem às funçõesAuto Lisp cuja execução antecede a das nossas funções.29 A listagem apre-sentada pelo Visual Lisp mostra, por ordem inversa, as invocações de fun-ções que provocaram o erro. Para cada linha, o Visual Lisp disponibilizaum menu contextual que, entre outras operações, permite visualizarmosimediatamente no editor qual é a linha do programa em questão.

A leitura da listagem do error trace diz-nos que o erro foi provocadopela tentativa de somarmos nil a um número. Essa tentativa foi feita pelafunção +xy que foi invocada pela função fuste que foi invocada pela fun-ção coluna que, finalmente, foi invocada pela função coluna-standard.Como podemos ver, à frente do nome de cada função, aparecem os argu-mentos com que a função foi invocada. Estes argumentos mostram que oerro de que o Auto Lisp se queixa na soma, na realidade, foi provocadomuito antes disso, logo na invocação da função coluna. De facto, é visívelque essa função é invocada com um ponto cuja coordenada x é nil e nãoum número como devia ser. Esta é a pista que nos permite identificar oerro: ele tem de estar na própria função coluna-standard e, mais espe-cificamente, na expressão que cria as coordenadas que são passadas comoargumento da função coluna. Se observarmos cuidadosamente essa ex-pressão (que assinalámos a negrito) vemos que, de facto, está lá um muitosubtil erro: o primeiro argumento da função xy não é zero mas sim a letra“ó” maiúsculo.

28A expressão error trace pode ser traduzida para “Rastreio de erros.”29Essas funções que foram invocadas antes das nossas revelam que, na verdade, parte da

funcionalidade do Visual Lisp está ela própria implementada em Auto Lisp.

88

Page 90: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(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 não tenha sido previ-amente definido tem o valor nil e, como o nome constituído pela letra Onão está definido, a avaliação do primeiro argumento da função xy é, naverdade, nil. Esta função, como se limita a fazer uma lista com os seusargumentos, cria uma lista cujo primeiro elemento é nil e cujo segundoelemento é zero. A lista resultante é assim passada de função em funçãoaté chegarmos à função +xy que, ao tentar fazer a soma, acaba por provo-car o erro.

Esta “sessão” de depuração mostra o procedimento habitual para de-tecção de erros. A partir do momento em que o erro é identificado, é ge-ralmente fácil corrigi-lo mas convém ter presente que o processo de iden-tificação de erros pode ser moroso e frustrante. É também um facto quea experiência de detecção de erros é extremamente útil e que, por isso, éexpectável que enquanto essa experiência for reduzida, o processo de de-tecção seja mais lento.

5 Modelação Tridimensional

Como vimos na secção anterior, o AutoCad disponibiliza um conjunto deoperações de desenho (linhas, rectângulos, círculos, etc) que nos permi-tem facilmente criar representações bidimensionais de objectos, como se-jam plantas, alçados e cortes.

Embora até este momento apenas tenhamos utilizado as capacidadesde desenho bi-dimensional do AutoCad, é possível irmos mais longe, en-trando no que se denomina por modelação tridimensional. Esta modelaçãovisa a representação gráfica de linhas, superfícies e volumes no espaço tri-dimensional.

Nesta secção iremos estudar as operações do AutoCad que nos permi-tem modelar directamente os objectos tridimensionais.

5.1 Sólidos Tridimensionais Pré-Definidos

As versões mais recentes do AutoCad disponibilizam um conjunto de ope-rações pré-definidas que constroem um sólido a partir da especificação dassuas coordenadas tridimensionais. Embora as operações pré-definidas ape-nas permitam construir um conjunto muito limitado de sólidos, esse con-junto é suficiente para a elaboração de modelos sofisticados.

89

Page 91: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

As operações pré-definidas para criação de sólidos permitem construirparalelipípedos (comando box), cunhas (comando wedge), cilindros (co-mando cylinder), cones (comando cone), esferas (comando sphere),toros (comando torus) e pirâmides (comando pyramid). Os comandoscone e pyramid permitem ainda a construção de troncos de cone e troncosde pirâmide através da utilização do parâmetro "Top". Cada um destes co-mandos aceita várias opções que permitem construir sólidos de diferentesmaneiras.30 A Figura 20 mostra um conjunto de sólidos construídos pelaavaliação das seguintes expressões:31

(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 sólidos, nomeadamente o paralelipípedo e acunha só podem ser construídos com a base paralela ao planoXY . Esta nãoé uma verdadeira limitação do AutoCad pois é possível alterar a orientaçãodo planoXY através da manipulação do sistema de coordenadas UCS–usercoordinate system.

A partir dos comandos disponibilizados pelo AutoCad é possível de-finir funções Auto Lisp que simplifiquem a sua utilização. Embora o Au-toCad permita vários modos diferentes de se criar um sólido, esses modosestão mais orientados para facilitar a vida ao utilizador do AutoCad do quepropriamente para o programador de Auto Lisp. Para este último, é pre-ferível dispor de uma função que, a partir de um conjunto de parâmetrossimples, invoca o comando correspondente em AutoCad, especificando au-tomaticamente as opções adequadas para a utilização desses parâmetros.

Para vermos um exemplo, consideremos a criação de um cilindro. Em-bora o AutoCad permita construir o cilindro de várias maneiras diferentes,

30Para se conhecer as especificidades de cada comando recomenda-se a consulta da do-cumentação que acompanha o AutoCad.

31A construção de uma pirâmide exige a especificação simultânea do raio e ângulo dabase. Tal como explicado na secção 4.14, a função raio&angulo constrói essa especificaçãoa partir dos valores do raio e do ângulo.

90

Page 92: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 20: Sólidos primitivos em AutoCad.

cada uma empregando diferentes parâmetros, podemos considerar que osúnicos parâmetros relevantes são o centro da base, o raio da base e o centrodo topo. Estes parâmetros são suficientes para especificar completamenteum cilindro, permitindo orientá-lo no espaço como muito bem entender-mos. Assim, para o programador de Auto Lisp, basta-lhe invocar o co-mando AutoCad cylinder seleccionando o modo de construção que faci-lita o uso deste parâmetros. É precisamente isso que faz a seguinte função:

(defun cilindro (centro-base raio centro-topo)(command "_cylinder" centro-base raio "_Axis" centro-topo))

Usando esta função é agora mais simples definir outras estruturas maiscomplexas. Por exemplo, uma cruz papal define-se pela união de três cilin-dros horizontais de comprimento progressivamente decrescente dispostosao longo de um cilindro vertical, tal como se pode ver na Figura 21. É desalientar que os cilindros têm todos o mesmo raio e que o seu comprimentoe posicionamento é função desse raio. Em termos de proporção, o cilindrovertical da cruz papal tem um comprimento igual a 20 raios, enquanto queos cilindros horizontais possuem comprimentos iguais a 14, 10 e 6 raios

91

Page 93: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 21: Uma cruz papal.

e o seu eixo está posicionado a uma altura igual a 9, 13 e 17 raios. Estasproporções são implementadas pela seguinte função:

(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 representações tri-dimensionais está no factode elas conterem toda a informação necessária para a geração automáticade vistas bi-dimensionais, incluindo as tradicionais projecções ortogonais.Para isso, o AutoCad permite diferentes abordagens, desde a simples utili-zação de múltiplas vistas (através do comando mview), cada uma com uma

92

Page 94: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 22: Alçado frontal, lateral e planta da cruz papal representada naFigura 21.

perspectiva diferente, até a criação automática de projecções e cortes (co-mandos solview, soldraw, flatshot e sectionplane, entre outros).A Figura 22 mostra o alçado frontal, o alçado lateral e a planta produzidosautomaticamente pelo comando flatshot a partir do modelo apresen-tado na Figura 21.

Exercício 5.1.1 Defina uma função denominada prisma que cria um sólido prismático re-gular. A função deverá receber o número de lados do prisma, as coordenadas tridimensio-nais do centro da base do prisma, a distância do centro da base a cada vértice, o ângulo derotação da base do prisma e as coordenadas tridimensionais do centro do topo do prisma.

A título de exemplo, considere as expressões(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 avaliação produz a imagem seguinte:

93

Page 95: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

5.2 Modelação de Colunas Dóricas

A modelação tri-dimensional tem a virtude de nos permitir criar entidadesgeométricas muito mais realistas do que meros aglomerados de linhas arepresentarem vistas dessas entidades. A título de exemplo, reconsidere-mos a coluna Dórica que apresentámos na secção 4.16. Nessa secção desen-volvemos um conjunto de funções cuja invocação criava uma vista frontaldos componentes da coluna Dórica. Apesar dessas vistas serem úteis, éainda mais útil poder modelar directamente a coluna como uma entidadetri-dimensional.

Nesta secção vamos empregar algumas das operações mais relevantespara a modelação tri-dimensional de colunas, em particular, a criação detroncos de cone para modelar o fuste e o coxim e a criação de paralelipípe-dos 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á apenasa base das colunas que ficará assente no plano x-y: o corpo das colunasirá desenvolver-se ao longo do eixo dos z. Embora fosse trivial empregaroutro arranjo dos eixos do sistema de coordenadas, este é aquele que é maispróximo da realidade.

À semelhança de inúmeras outras operações do AutoCad, cada uma

94

Page 96: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

das operações de modelação de sólidos do AutoCad permite vários modosdiferentes de invocação. No caso da operação de modelação de troncosde cone—cone—o modo que nos é mais conveniente é aquele em que aoperação recebe as coordenadas do centro da base do cone e o raio dessabase e, de seguida, especificamos o raio do topo do cone (com a opçãoTop radius) e, finalmente, a altura do tronco.

Tendo isto em conta, podemos redefinir a operação que constrói o fustetal como se segue:

(defun fuste (p a-fuste r-base r-topo)(command "_.cone" p r-base

"_t" r-topo a-fuste))

Do mesmo modo, a operação que constrói o coxim ficará 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 ábaco—o paralelipípedo que é co-locado no topo da coluna—temos várias maneiras de o especificarmos. Amais directa consiste em indicar os dois cantos do paralelipípedo. Uma ou-tra, menos directa, consiste em indicar o centro do paralelipípedo seguidodo 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)))

Exercício 5.2.1 Implemente a função abaco mas empregando a criação de um paralelipí-pedo centrado num ponto seguido da especificação do seu comprimento, largura e altura.

Finalmente, falta-nos implementar a função coluna que, à semelhançado que fazia no caso bi-dimensional, invoca sucessivamente as funçõesfuste, coxim e abaco mas, agora, elevando progressivamente a coor-denada z:

(defun coluna (pa-fuste r-base-fustea-coxim r-base-coxima-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))

95

Page 97: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 23: Modelação tri-dimensional das variações de colunas dóricas.

Com estas redefinições, podemos agora repetir as colunas que desenhá-mos na secção 4.17 e que apresentámos na Figura 19, mas, agora, gerandouma imagem tri-dimensional dessas mesmas colunas, tal como apresenta-mos 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 Auto-Cad para extrair qualquer vista que pretendamos, incluindo perspectivascomo a que apresentamos na Figura 24.

6 Expressões Condicionais

Existem muitas operações cujo resultado depende da realização de um de-terminado teste. Por exemplo, a função matemática |x|—que calcula o valorabsoluto de um número—equivale ao próprio número, se este é positivo,ou equivale ao seu simétrico se for negativo. Esta função terá, portanto de

96

Page 98: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 24: Perspectiva da modelação tri-dimensional das variações de co-lunas dóricas.

testar o seu argumento e escolher uma de duas alternativas: ou devolve opróprio argumento, ou devolve o seu simétrico.

Estas expressões, cujo valor depende de um ou mais testes a realizarpreviamente, permitindo escolher vias diferentes para a obtenção do resul-tado, são designadas expressões condicionais.

No caso mais simples de uma expressão condicional, existem apenasduas alternativas a seguir. Isto implica que o teste que é necessário realizarpara determinar a via de cálculo a seguir deve produzir um de dois valores,em que cada valor designa uma das vias.

Seguindo o mesmo raciocício, uma expressão condicional com mais deduas alternativas deverá implicar um teste com igual número de possíveisresultados. Uma expressão da forma “caso o valor do teste seja 1, 2 ou 3,o valor da expressão é 10, 20 ou 30, respectivamente” é um exemplo destacategoria de expressões que existe nalgumas linguagens (Basic, por exem-plo). Contudo, estas expressões podem ser facilmente reduzidas à primeiraatravés da decomposição da expressão condicional múltipla numa compo-sição de expressões condicionais simples, em que o teste original é tambémdecomposto numa série de testes simples. Assim, poderiamos transformaro exemplo anterior em: “se o valor do teste é 1, o resultado é 10, caso con-trário, se o valor é 2, o resultado é 20, caso contrário é 30”.

97

Page 99: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

6.1 Expressões Lógicas

Desta forma, reduzimos todos os testes a expressões cujo valor pode serapenas um de dois, e a expressão condicional assume a forma de “se . . . então. . . caso contrário . . . .” A expressão cujo valor é usado para decidir se deve-mos usar o ramo “então” ou o ramo “caso contrário” denomina-se expressãológica e caracteriza-se por o seu valor ser interpretado como verdade ou falso.Por exemplo, a expressão lógica (> x y) testa se o valor de x é maior queo valor de y. Se for, a expressão avalia para verdade, caso contrário avaliapara falso.

6.2 Valores Lógicos

Algumas linguagens de programação consideram a verdade e o falso comodois elementos de um tipo especial de dados denominado lógico ou boole-ano.32 Outras linguagens, como o Lisp, entendem que o facto de se con-siderar um valor como verdadeiro ou falso não implica necessariamenteque o valor tenha de ser de um tipo de dados especial, mas apenas que aexpressão condicional considera alguns dos valores como representando overdadeiro e os restantes como o falso.

Em Lisp, as expressões condicionais consideram como falso um únicovalor. Esse valor é representado por nil, o mesmo valor que usámos ante-riormente para representar uma lista vazia. Qualquer outro valor diferentede nil é considerado como verdadeiro. Assim, do ponto de vista de umaexpressão condicional, o número 123, por exemplo, é um valor verdadeiro.Contudo, não faz muito sentido para o utilizador humano considerar umnúmero como verdadeiro ou falso, pelo que se introduziu uma constantena linguagem para representar verdade. Essa constante representa-se port. A lógica é que se t é diferente de nil e se nil é o único valor querepresenta a falsidade, então t representa necessariamente a verdade.

6.3 Predicados

No caso mais usual, uma expressão lógica é uma invocação de função comdeterminados argumentos. Nesta situação, a função usada como teste édenominada predicado e o valor do teste é interpretado como sendo verda-deiro ou falso. O predicado é, consequentemente, uma função que devolveapenas verdade ou falso.

32De George Boole, matemático inglês e inventor da álgebra da verdade e da falsidade.

98

Page 100: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Apesar da adopção dos símbolos t e nil, convém alertar que nem to-dos os predicados devolvem t ou nil exclusivamente. Alguns há que,quando querem indicar verdade, devolvem valores diferentes de t (e denil, obviamente).

6.4 Predicados Aritméticos

Os operadores relacionais matemáticos <, >, =, ≤, ≥ e 6= são um dos exem-plos mais simples de predicados. Estes operadores comparam númerosentre si e permitem saber se um número é menor que outro. O seu uso emLisp segue as regras da notação prefixa e escrevem-se, respectivamente, <,>, =, <=, >= e /=. Eis alguns exemplos:

_$ (> 4 3)t_$ (< 4 3)nil_$ (<= (+ 2 3) (- 6 1))t

6.5 Operadores Lógicos

Para se poder combinar expressões lógicas entre si existem os operadoresand, or e not. O and e o or recebem qualquer número de argumentos. Onot só recebe um. O valor das combinações que empregam estes operado-res lógicos é determinado do seguinte modo:

• O and avalia os seus argumentos da esquerda para a direita até queum deles seja falso, devolvendo este valor. Se nenhum for falso o anddevolve verdade.

• O or avalia os seus argumentos da esquerda para a direita até que umdeles seja verdade, devolvendo este valor. Se nenhum for verdade oor devolve falso.

• O not avalia para verdade se o seu argumento for falso e para falsoem caso contrário.

Note-se que embora o significado de falso seja claro pois correspondenecessariamente ao valor nil, o significado de verdade já não é tão claropois, desde que seja diferente de nil, é considerado verdade.

Exercício 6.5.1 Qual o valor das seguintes expressões?

99

Page 101: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

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 número variável de argumentos

Uma propriedade importante dos predicados aritméticos <, >, =, <=, >= e/= é aceitarem qualquer número de argumentos. No caso em que há maisdo que um argumento, o predicado é aplicado sequencialmente aos paresde argumentos. Assim, (< e1 e2 e3 ... en−1 en) é equivalente a escre-ver (and (< e1 e2) (< e2 e3) ... (< en−1 en)). Este comportamentoé visível nos sequintes exemplos.

_$ (< 1 2 3)T_$ (< 1 2 2)nil

Um caso particular que convém ter em atenção é que embora a expres-são (= e1 e2 ... en) teste se os elementos e1 e2 . . . en são todos iguais,(/= e1 e2 ... en) não testa se os elementos e1 e2 . . . en são todos dife-rentes: uma vez que o teste é aplicado sucessivamente a pares de elementosé perfeitamente possível que existam dois elementos iguais desde que nãosejam consecutivos. Esse comportamento é visível no seguinte exemplo:33

_$ (/= 1 2 3)T_$ (/= 1 2 1)T

6.7 Predicados sobre Cadeias de Caracteres

Na verdade, os operadores <, >, =, <=, >= e /= não se limitam a operaremsobre números: eles aceitam também cadeias de caracteres como argumen-tos, fazendo uma comparação lexicográfica: os argumentos são comparados

33Outros dialectos de Lisp apresentam um comportamento diferente para esta operação.Em Common Lisp, por exemplo, o predicado /= testa se, de facto, os argumentos são todosdiferentes.

100

Page 102: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

carácter a carácter enquanto forem iguais. Quando são diferentes, a ordemléxicografica do primeiro carácter diferente nas duas strings determina ovalor lógico da relação. Se a primeira string “acabar” antes da segunda,considera-se que é “menor,” caso contrário, é “maior.”

_$ (= "pois" "pois")T_$ (= "pois" "poisar")nil_$ (< "pois" "poisar")T_$ (< "abcd" "abce")T

6.8 Predicados sobre Símbolos

Para além de números e strings, o predicado = permite ainda compararsímbolos.

_$ (= ’pois ’pois)T_$ (= ’pois ’poisar)nil

Nenhum dos outros operadores relacionais é aplicável a símbolos.

6.9 Predicados sobre Listas

Vimos que os dados manipulados pelo Lisp se podiam classificar em ató-micos ou não-atómicos consoante era impossível, ou não, aplicar-lhes asoperações de listas car e cdr.

Para facilitar a identificação das entidades atómicos, a linguagem Lispdisponibiliza uma função denominada atom que só é verdadeira para asentidades atómicas:

_$ (atom 1)T_$ (atom "dois")T_$ (atom ’quatro)T_$ (atom (cons 1 "dois"))nil_$ (atom (list 1 "dois" 3.0))nil

101

Page 103: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

_$ (atom ())T_$ (atom t)T_$ (atom nil)T

A função atom permite-nos, assim, saber quais os tipos de entidades aque podemos aplicar as operações car e cdr: apenas aquelas que não sãoátomos.

6.10 Reconhecedores

Para além dos operadores relacionais, existem muitos outros predicadosem Lisp, como por exemplo o zerop que testa se um número é zero:

_$ (zerop 1)nil_$ (zerop 0)t

O facto de zerop terminar com a letra “p” deve-se a uma convençãoadoptada em Lisp segundo a qual os predicados cujo nome seja uma oumais palavras devem ser distinguidos das restantes funções através da con-catenação da letra “p” (de Predicate) ao seu nome. Infelizmente, por moti-vos históricos, nem todos os predicados pré-definidos seguem esta conven-ção. No entanto, nos predicados que definirmos devemos ter o cuidado deseguir esta convenção.

Note-se que o operador zerop serve para reconhecer um elemento emparticular (o zero) de um tipo de dados (os números). Este género de pre-dicados denominam-se de reconhecedores. Um outro exemplo de um reco-nhecedor é o predicado null que reconhece a lista vazia. A função nulldevolve verdade quando aplicada a uma lista vazia e falso em qualqueroutro caso:

_$ (list 1 2 3)(1 2 3)_$ (null (list 1 2 3))nil_$ (list)nil_$ (null (list))T

102

Page 104: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Para se perceberem as duas últimas expressões do exemplo anteriorconvém recordar que nil representa não só a falsidade mas também a listavazia.

6.11 Reconhecedores Universais

Um outro conjunto importante de predicados são os denominados reconhe-cedores universais. Estes não reconhecem elementos particulares de um tipode dados mas sim todos os elementos de um particular tipo de dados. Umreconhecedor universal aceita qualquer tipo de valor como argumento edevolve verdade se o valor é do tipo pretendido.

Por exemplo, para sabermos se uma determinada entidade é um nú-mero podemos empregar o predicado numberp:34

_$ (numberp 1)T_$ (numberp nil)nil_$ (numberp "Dois")nil

Para testar se uma determinada entidade é uma lista podemos empre-gar o predicado listp. Este predicado é verdade para qualquer lista (in-cluindo 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 tam-bém considera como lista um mero par de elementos. Na realidade, estereconhecedor devolve verdade sempre que o seu argumento é um dottedpair ou o nil. As listas, como vimos, não são mais do que arranjos particu-lares de dotted pairs ou, no limite, uma lista vazia.

34É tradicional, em vários dialectos de Lisp, terminar o nome dos predicados com a letrap. Noutros dialectos, prefere-se terminar esse nome com um ponto de interrogação precisa-mente porque, na prática, a invocação de um predicado corresponde a uma pergunta quefazemos. Neste texto, nos casos em que fizer sentido enquadrarmo-nos com a tradição, ire-mos empregar a letra p; em todos os outros casos iremos empregar o ponto de interrogação.

103

Page 105: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Para a maioria dos tipos, o Auto Lisp não providencia nenhum reconhe-cedor universal, antes preferindo usar a função genérica type que devolveo nome do tipo como símbolo. Como vimos na seccção 3.14, temos:

_$ (type pi)REAL_$ (type 1)INT_$ (type "Ola")STR_$ (type quadrado)USUBR_$ (type +)SUBR

Obviamente, nada nos impede de definir os reconhecedores universaisque pretendermos. À semelhança do predicado numberp podemos definiros seus subcasos integerp e realp:

(defun integerp (obj)(= (type obj) ’int))

(defun realp (obj)(= (type obj) ’real))

É igualmente trivial definir um reconhecedor universal de strings e ou-tro para funções (compiladas ou não):

(defun stringp (obj)(= (type obj) ’str))

(defun functionp (obj)(or (= (type obj) ’subr)

(= (type obj) ’usubr)))

6.12 Exercícios

Exercício 6.12.1 O que é uma expressão condicional? O que é uma expressão lógica?

Exercício 6.12.2 O que é um valor lógico? Quais são os valores lógicos empregues em AutoLisp?

Exercício 6.12.3 O que é um predicado? Dê exemplos de predicados em Auto Lisp.

Exercício 6.12.4 O que é um operador relacional? Dê exemplos de operadores relacionaisem Auto Lisp.

104

Page 106: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Exercício 6.12.5 O que é um operador lógico? Quais são os operadores lógicos que conheceem Auto Lisp?

Exercício 6.12.6 O que é um reconhecedor? O que é um reconhecedor universal? Dê exem-plos em Auto Lisp.

Exercício 6.12.7 Traduza para Lisp as seguintes expressões matemáticas:

1. x < y

2. x ≤ y3. x < y ∧ y < z

4. x < y ∧ x < z

5. x ≤ y ≤ z6. x ≤ y < z

7. x < y ≤ z

7 Estruturas de Controle

Até agora, temos visto essencialmente a definição e aplicação de funções.No caso da aplicação de funções, vimos que o Lisp avalia todos os elemen-tos da combinação e, em seguida, invoca a função que é o resultado daavaliação do primeiro elemento da combinação usando, como argumentos,o resultado da avaliação dos restantes elementos. Este comportamento éimposto pela linguagem e é um exemplo de uma estrutura de controle.

Em termos computacionais, o controle está associado à ordem pela qualo computador executa as instruções que lhe damos. Se nada for dito emcontrário, o computador executa sequencialmente as instruções que lhe da-mos. No entanto, algumas dessas instruções podem provocar o salto de ins-truções, i.e., podem forçar o computador a continuar a executar instruçõesmas a partir de outro ponto do programa.

Com o tempo, os programadores aperceberam-se que a utilização indis-criminada de saltos tornava os programas extremamente difíceis de com-preender por um ser humano e, por isso, inventaram-se formas mais estru-turadas de controlar o computador: as estruturas de controle.

As estruturas de controle não são mais do que formas padronizadas dese controlar um computador. Esta estruturas de controle não são disponi-bilizadas pelo computador em si mas sim pela linguagem de programaçãoque estivermos a utilizar que, depois, as converte nas estruturas de controlebásicas do computador.

Iremos agora ver algumas das estruturas de controle mas importantes.

105

Page 107: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

7.1 Sequenciação

A estrutura de controle mais simples que existe é a sequenciação.Na estrutura de controle de sequenciação, o Lisp avalia uma sequência

de expressões uma a seguir à outra, devolvendo o valor da última. Logica-mente, se apenas o valor da última expressão é utilizado, então os valoresde todas as outras avaliações dessa sequência são descartados e estas ape-nas são relevante pelos efeitos secundários que possam provocar.

Como já vimos, é possível usar sequenciação na definição de uma fun-ção. Esta função, quando invocada, irá sucessivamente avaliar cada umadas expressões, descartando o seu valor, até chegar à última que será ava-liada e o seu valor será considerado como o valor da invocação da função.

Aquando da definição da coluna dórica, vimos que a função colunausava sequenciação para desenhar, sucessivamente, o fuste, o coxim e oábaco:

(defun coluna (pa-fuste r-base-fustea-coxim r-base-coxima-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))

Como se pode ver, a função recebe vários parâmetros necessários paraespecificar completamente as características geométricas da coluna.

Quando invocada, a função coluna limita-se a, primeiro, invocar afunção fuste, passando-lhe os argumentos relevantes, segundo, invocar afunção coxim, passando-lhe os argumentos relevantes e, terceiro, invocara função abaco, passando-lhe os argumentos relevantes. É precisamenteeste “primeiro,” “segundo,” “terceiro” que caracteriza a estrutura de con-trole de sequenciação: as avaliações são feitas sequencialmente.

Se tivermos em conta que uma função, quando invocada, precisa decomputar e devolver um valor, a presença de sequenciação levanta a per-gunta sobre qual dos valores que foram sucessivamente computados é querepresenta o valor da função invocada: por conveniência, Lisp arbitra queé o último e todos os anteriores são descartados.

Embora o corpo de uma função possa conter várias expressões que,quando a função é invocada, são avaliadas sequencialmente, na realidade,a sequenciação é implementada em Lisp através de um operador denomi-nado progn:

106

Page 108: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

_$ (progn(+ 1 2)(* 3 4))

12

Este operador recebe várias expressões como argumento que avalia se-quencialmente, devolvendo o valor da última. Quando definimos uma fun-ção todas as expressões que colocamos no corpo da função são avaliadasnum progn implícito. Como iremos ver, existem ainda outras formas dalinguagem Lisp que possuem progns implícitos.35

7.2 Invocação de Funções

A invocação de uma função é a estrutura de controle mais usada em Lisp.Para se invocar uma função, é necessário construir uma combinação

cujo primeiro elemento seja uma expressão que avalia para a função quese pretende invocar e cujos restantes elementos são expressões que ava-liam para os argumentos que se pretende passar à função. O resultado daavaliação da combinação é o valor calculado pela função para aqueles ar-gumentos.

A avaliação de uma combinação deste género processa-se nos seguintespassos:

1. Todos os elementos da combinação são avaliados, sendo que o valordo primeiro elemento é necessariamente uma função.

2. Associam-se os parâmetros formais dessa função aos argumentos,i.e., aos valores dos restantes elementos da combinação. Cada pa-râmetro é associado a um argumento, de acordo com a ordem dosparâmetros e argumentos. É gerado um erro sempre que o númerode parâmetros não é igual ao número de argumentos.

3. Avalia-se o corpo da função tendo em conta estas associações entre osparâmetros e os argumentos.

35O nome progn parece pouco intuitivo mas, como a maioria dos nomes usados emLisp, tem uma história que o justifica. Os Lisps originais disponibilizavam um operadordenominado prog (abreviatura de “program”) que, entre várias outras coisas, permitiasequenciação. Para além deste operador, foram introduzidas variantes mais simples, deno-minadas prog1—que avaliava sequencialmente os seus argumentos e retornava o valor daprimeira—, prog2—que avaliava sequencialmente os seus argumentos e retornava o valorda segunda—e, finalmente, progn—que avaliava sequencialmente os seus argumentos eretornava o valor da última. Apenas este último operador foi implementado em Auto Lisp.

107

Page 109: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Para exemplificar, consideremos a definição da função quadrado e aseguinte combinação:

_$ (defun quadrado (x) (* x x))QUADRADO_$ (+ 1 (quadrado 2) 3)

Para que o avaliador de Lisp consiga avaliar a última combinação ne-cessita de começar por avaliar todos os seus elementos. O primeiro, osímbolo +, avalia para o procedimento que realiza somas mas, antes depoder fazer a soma, precisa de determinar os seus argumentos através daavaliação dos restantes elementos da combinação. O primeiro argumentoé o número 1 pois, como vimos anteriormente, o valor de um número éo próprio número. Depois de avaliar o primeiro argumento, o avaliadordepara-se com uma nova combinação. Nesse momento, suspende a avalia-ção que estava a fazer e inicia uma nova avaliação, agora para a combinação(quadrado 2). Novamente, porque se trata da aplicação de uma função,o avaliador vai avaliar todos os seus argumentos que, neste caso, é apenasum número que avalia para ele próprio. A partir deste momento, o controleé transferido para o corpo da função quadrado, mas fazendo a associaçãodo parâmetro x ao valor 2. A avaliação do corpo da função quadrado im-plica a avaliação da combinação (* x x). Trata-se de uma multiplicaçãocujos argumentos são obtidos pela repetida avaliação do símbolo x. Umavez que a invocação da função tinha associado x ao argumento 2, o valorde x é 2. No entanto, para realizar a multiplicação é necessário ter em contaque se trata, mais uma vez, da invocação de uma função, pelo que a ava-liação da invocação da função quadrado é por sua vez suspensa para sepassar à avaliação da multiplicação. No instante seguinte, a multiplicaçãoé realizada e tem como resultado o número 4. Nesse momento, o avaliadortermina a invocação da multiplicação e faz o controle regressar à avalia-ção do quadrado de 2. Uma vez que a multiplicação é a última expressãoda função quadrado, esta invocação vai também terminar tendo como re-sultado o mesmo da multiplicação, i.e., 4. Mais uma vez, o avaliador vaitransferir o controle, agora para a expressão que estava a avaliar quandoinvocou a função quadrado, avaliando o último argumento da soma (queavalia para ele próprio), permitindo-lhe assim concluir a soma com o valor8.

Resumidamente, a invocação de funções consiste em “suspender” aavaliação que se estava a fazer para (1) se associarem os argumentos da in-vocação aos parâmetros da função invocada, (2) avaliar o corpo da funçãotendo aquela associação em conta e (3) “retomar” a avaliação suspendida

108

Page 110: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

usando como valor da invocação o valor da última expressão do corpo dafunção invocada.

As características da linguagem Lisp tornam-na particularmente apta àdefinição e invocação de funções. De facto, as bases matemáticas da lingua-gem Lisp assentam precisamente sobre o conceito de função. Em Lisp, asfunções usam-se não só por uma questão de conveniência mas também poruma questão de modelação: uma função representa algo que devemos tornarclaro. 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 função estamos a exprimir uma depen-dência entre entidades. Uma dessas entidades diz-se então função das res-tantes e o seu valor é determinado pela invocação de uma função que re-cebe as restantes entidades como argumentos.

7.3 Variáveis Locais

Consideremos o seguinte triângulo

c b

a

e tentemos definir uma função Auto Lisp que calcula a área do triângulo apartir dos parâmetros a, b e c.

Uma das formas de calcular a área do triângulo baseia-se na famosafórmula de Heron:36

A =√s (s− a) (s− b) (s− c)

em que é s o semi-perímetro do triângulo:

s =a+ b+ c

236Heron de Alexandria foi um importante matemático e engenheiro Grego do primeiro

século depois de Cristo a quem se atribuem inúmeras descobertas e invenções, incluindo amáquina a vapor e a seringa.

109

Page 111: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Ao tentarmos usar a fórmula de Heron para definir a correspondentefunção Auto Lisp, somos confrontados com uma dificuldade: a fórmulaestá escrita (também) em termos do semi-perímetro s mas s não é um pa-râmetro, é um valor derivado dos parâmetros do triângulo.

Uma das maneira de resolvermos este problema consiste em eliminar avariável s, substituindo-a pelo seu significado:

A =

√a+ b+ c

2

(a+ b+ c

2− a)(

a+ b+ c

2− b)(

a+ b+ c

2− c)

A partir desta fórmula já é possível definir a função pretendida:

(defun area-triangulo (a b c)(sqrt (* (/ (+ a b c) 2)

(- (/ (+ a b c) 2) a)(- (/ (+ a b c) 2) b)(- (/ (+ a b c) 2) c))))

Infelizmente, esta definição tem dois problemas. O primeiro é que seperdeu a correspondência entre a fórmula original e a definição da função,tornando mais difícil reconhecer que a função está a implementar a fórmulade Heron. O segundo problema é que a função é obrigada a repetidamenteempregar a expressão (/ (+ a b c) 2), o que não só representa um des-perdício do nosso esforço, pois tivemos de a escrever quatro vezes, comorepresenta um desperdício de cálculo, pois a expressão é calculada quatrovezes, embora saibamos que ela produz sempre o mesmo resultado.

Para resolver estes problemas, o Auto Lisp permite a utilização de va-riáveis locais. Uma variável local é uma variável que apenas tem signifi-cado dentro de uma função e que é usada para calcular valores intermédioscomo o do semi-perímetro s. Empregando uma variável local, podemos re-escrever a função area-triangulo da seguinte forma:

(defun area-triangulo (a b c / s)(setq s (/ (+ a b c) 2))(sqrt (* s (- s a) (- s b) (- s c))))

Na definição anterior há dois aspectos novos que vamos agora discu-tir: a declaração da variável local s e a atribuição dessa variável através dooperador setq.

Para se indicar que uma função vai usar variáveis locais, estas têm deser declaradas conjuntamente com a lista de parâmetros da função. Paraisso, vamos agora ampliar a sintaxe da definição de funções que apresen-támos anteriormente (na secção 3.6 de modo a incorporar a declaração devariáveis locais:

110

Page 112: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(defun nome (parâmetro1 ... parâmetron/ variável1 ... variávelm)

corpo)

Note-se que as variáveis locais são separadas dos parâmetros por umabarra. É necessário ter o cuidado de não “colar” a barra nem ao últimoparâmetro nem à primeira variável sob pena de o Auto Lisp considerar abarra como parte de um dos nomes (e, consequentemente, tratar as variá-veis locais como se de parâmetros se tratasse).

Embora seja raro, é perfeitamente possível termos funções sem parâ-metros mas com variáveis locais. Neste caso, a sintaxe da função seria sim-plesmente:

(defun nome (/ variável1 ... variávelm)corpo)

7.4 Atribuição

Para além da declaração de uma variável local é ainda necessário atribuir-lhe um valor, i.e., realizar uma operação de atribuição. Para isso, o AutoLisp disponibiliza o operador setq, cuja sintaxe é:

(setq variável1 expressão1

...variávelm expressãom)

A semântica deste operador consiste simplesmente em avaliar a expres-são expressão1 e associar o seu valor ao nome variável1, repetindo esteprocesso para todas as restantes variáveis e valores.

A utilização que fazemos deste operador na função area-trianguloé fácil de compreender:

(defun area-triangulo (a b c / s)(setq s (/ (+ a b c) 2))(sqrt (* s (- s a) (- s b) (- s c))))

Ao invocarmos a função area-triangulo, passando-lhe os argumen-tos correspondentes aos parâmetros a, b e c, ela começa por introduzir umnovo nome—s—que vai existir apenas durante a invocação da função. Deseguida, atribui a esse nome o valor que resultar da avaliação da expres-são (/ (+ a b c) 2). Finalmente, avalia as restantes expressões do corpoda função. Na prática, é como se a função dissesse: “Sendo s = a+b+c

2 ,calculemos

√s (s− a) (s− b) (s− c).”

111

Page 113: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Há dois detalhes que é importante conhecer relativamente às variáveislocais. O primeiro detalhe, que iremos discutir mais em profundidade napróxima secção, é que se nos esquecermos de declarar a variável, ela serátratada como variável global. O segundo detalhe é que se nos esquecermosde atribuir a variável ela fica automaticamente com o valor nil. Logica-mente, para que uma variável nos seja útil, devemos mudar o seu valorpara algo que nos interesse.

Para visualizarmos um exemplo mais complexo, consideremos a equa-ção do segundo grau

ax2 + bx+ c = 0

Como sabemos, esta equação tem duas raízes que se podem obter pela fa-mosa fórmula resolvente:

x =−b+

√b2 − 4ac

2a∨ x =

−b−√b2 − 4ac

2a

Dada a utilidade desta fórmula, podemos estar interessados em definiruma função que, dados os coeficientes a, b e c da equação do segundo graunos devolve as suas duas raizes. Para isso, vamos devolver um par denúmeros calculados usando as duas fórmulas 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))))

Por exemplo, usando a definição anterior, podemos calcular as soluçõesda equação (x − 2)(x − 3) = 0. De facto, esta equação é equivalente ax2 − 5x + 6 = 0, i.e., basta calcularmos as raízes empregando a fórmularesolvente com os coeficientes 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 ineficiência óbvia:a função raizes-equacao-segundo-grau calcula duas vezes o mesmovalor correspondente ao termo

√b2 − 4ac. Isso é perfeitamente visível na

dupla ocorrência da expressão (sqrt (- (quadrado b) (* 4 a c))).

112

Page 114: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Mais uma vez, é através do uso de variáveis locais e do operador setqque vamos simplificar e tornar mais eficiente esta função. Para isso, basta-nos calcular o valor de

√b2 − 4ac, associando-o a uma variável local e, em

seguida, usamos esse valor nos dois locais em que é necessário. Do mesmomodo, podemos declarar uma variável para conter o valor da expressão 2ae outra para conter −b. O resultado fica então:

(defun raizes-equacao-segundo-grau (a b c/ raiz-b2-4ac 2a -b)

(setq raiz-b2-4ac (sqrt (- (quadrado b) (* 4 a c)))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 são apenas nomesassociados a números que resultaram da avaliação das expressões corres-pondentes. Após estas atribuições, quando se vai avaliar a expressão queconstrói o par, esses nomes vão ser por sua vez avaliados e, logicamente,vão ter como valor a atribuição que lhes tiver sido feita anteriormente.

Um outro ponto importante a salientar é que aqueles nomes só existemdurante a invocação da função e, na realidade, existem diferentes ocorrên-cias daqueles nomes para diferentes invocações da função. Este ponto é decrucial importância para se perceber que, após a invocação da função, osnomes, quer de parâmetros, quer de variáveis locais, desaparecem, conjun-tamente com as associações que lhes foram feitas.

Exercício 7.4.1 Como viu, as variáveis locais permitem evitar cálculos repetidos. Uma ou-tra forma de evitar esses cálculos repetidos é através do uso de funções auxiliares. Rede-fina a função raizes-equacao-segundo-grau de forma a que não seja necessário usarquaisquer variáveis locais.

7.5 Variáveis Globais

Qualquer referência a um nome que não está declarado localmente implicaque esse nome seja tratado como uma variável global.37 O nome pi, porexemplo, representa a variável pi e pode ser usado em qualquer ponto dosnossos programas. Por esse motivo, o nome pi designa uma variável glo-bal.

37Na realidade, o Auto Lisp permite ainda uma terceira categoria de nomes que não sãonem locais, nem globais. Mais à frente discutiremos esse caso.

113

Page 115: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

A declaração de variáveis globais é mais simples que a das variáveis lo-cais: basta uma primeira atribuição, em qualquer ponto do programa, paraa variável ficar automaticamente declarada. Assim, se quisermos introdu-zir uma nova variável global, por exemplo, para definir a razão de ouro38

φ =1 +√

52

≈ 1.6180339887

basta-nos escrever:

(setq razao-de-ouro (/ (+ 1 (sqrt 5)) 2))

A partir desse momento, o nome razao-de-ouro pode ser referenci-ado em qualquer ponto dos programas.

É importante referir que o uso de variáveis globais deve ser restrito,na medida do possível, à definição de constantes, i.e., variáveis cujo valornunca muda como, por exemplo, pi. Outros exemplos que podem vir a serúteis incluem 2*pi, pi/2, 4*pi e pi/4, bem como os seus simétricos, quese definem à 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))

38Também conhecida por proporção divina e número de ouro, entre outras designações, eabreviada por φ em homenagem a Fineas, escultor Grego responsável pela construção doParténon onde, supostamente, usou esta proporção. A razão de ouro foi inicialmente in-troduzida por Euclides quando resolveu o problema de dividir um segmento de recta emduas partes de tal forma que a razão entre o segmento de recta e a parte maior fosse igual àrazão entre a parte maior e a menor. Se for a o comprimento do parte maior e b o da menor,o problema de Euclides é idêntico a dizer que a+b

a= a

b. Daqui resulta que a2 − ab− b2 = 0

ou que a =b±√b2+4b2

2= b 1±

√5

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

√5

2e,

consequentemente, a razão de ouro é φ = ab

= 1+√

52

.

114

Page 116: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

O facto de uma variável global ser uma constante implica que a variá-vel é atribuída uma única vez, no momento da sua definição. Esse factopermite-nos usar a variável sabendo sempre qual o valor a que ela está as-sociada. Infelizmente, por vezes é necessário usarmos variáveis globais quenão são constantes, i.e., o seu valor muda durante a execução do programa,por acção de diferentes atribuições feitas em locais diferentes e em momen-tos diferentes. Quando temos variáveis globais que são atribuidas em di-versos pontos do nosso programa, o comportamento deste pode tornar-semuito mais difícil de entender pois, na prática, pode ser necessário com-preender o funcionamento de todo o programa em simultâneo e não apenasfunção a função, como temos feito. Por este motivo, devemos evitar o usode variáveis globais que sejam atribuidas em vários pontos do programa.

7.6 Variáveis Indefinidas

A linguagem Auto Lisp difere da maioria dos outros dialecto de Lisp notratamento que dá a variáveis indefinidas, i.e., variáveis a que nunca foi atri-buído um valor.39Em geral, as linguagens de programação consideram quea avaliação de uma variável indefinida é um erro. No caso da linguagemAuto Lisp, a avaliação de qualquer variável indefinida é simplesmente nil.

A consequência deste comportamento é que existe o potencial de oserros tipográficos passarem despercebidos, tal como é demonstrado no se-guinte exemplo:

_$ (setq minha-lista (list 1 2 3))(1 2 3)_$ (cons 0 mimha-lista)(0)

Reparemos, no exemplo anterior, que a variável que foi definida não éa mesma que está a ser avaliada pois a segunda tem uma gralha no nome.Em consequência, a expressão 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, étambém a lista vazia.

Este género de erros pode ser extremamente difícil de detectar e, porisso, a maioria das linguagens abandonou este comportamento. O AutoLisp, por motivos históricos, manteve-o, o que nos obriga a termos de termuito cuidado para não cometermos erros que depois passem indetecta-dos.

39Na terminologia original do Lisp, estas variáveis diziam-se unbound.

115

Page 117: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 25: Perspectiva da modelação tri-dimensional de colunas cujos parâ-metros foram escolhidos aleatoriamente. Apenas uma das colunas obedeceaos cânones da Ordem Dórica.

7.7 Proporções de Vitrúvio

A modelação de colunas dóricas que desenvolvemos na secção 5.2 permite-nos facilmente construir colunas, bastando para isso indicarmos os valoresdos parâmetros relevantes, como a altura e o raio da base do fuste, a al-tura e raio da base do coxim e a altura e largura do ábaco. Cada um destesparâmetros constitui um grau de liberdade que podemos fazer variar livre-mente.

Embora seja lógico pensar que quantos mais graus de liberdade tiver-mos mais flexível é a modelação, a verdade é que um número excessivode parâmetros pode conduzir a modelos pouco realistas. Esse fenómenoé evidente na Figura 25 onde mostramos uma perspectiva de um conjuntode colunas cujos parâmetros foram escolhidos aleatoriamente.

Na verdade, de acordo com os cânones da Ordem Dórica, os diversosparâmetros que regulam a forma de uma coluna devem relacionar-se entresi segundo um conjunto de proporções bem definidas. Vitrúvio40, no seufamoso tratado de arquitectura, considera que essas proporções derivamdas proporções do próprio ser humano:

40Vitrúvio foi um escritor, arquitecto e engenheiro romano que viveu no século um antesde Cristo e autor do único tratado de arquitectura que sobreviveu a antiguidade.

116

Page 118: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Uma vez que pretendiam erguer um templo com colunasmas não tinham conhecimento das proporções adequadas, [. . . ]mediram o comprimento dum pé de um homem e viram queera um sexto da sua altura e deram à coluna uma proporçãosemelhante, i.e., fizeram a sua altura, incluindo o capitel, seisvezes a largura da coluna medida na base. Assim, a ordem Dó-rica obteve a sua proporção e a sua beleza, da figura masculina.

Mais concretamente, Vitrúvio caracteriza as colunas da Ordem Dóricaem termos do conceito de módulo:

• A largura das colunas, na base, será de dois modulos e a sua altura, incluindoos capitéis, será de catorze.

Daqui se deduz um módulo iguala o raio da base da coluna e que aaltura da coluna deverá ser 14 vezes esse raio. Dito de outra forma, oraio da base da coluna deverá ser 1

14 da altura da coluna.

• A altura do capitel será de um módulo e a sua largura de dois módulos e umsexto.

Isto implica que a altura do coxim somado à do ábaco será um mó-dulo, ou seja, igual ao raio da base da coluna e a largura do ábaco seráde 21

6 módulos ou 136 do raio. Juntamente com o facto de a altura da

coluna ser de 14 módulos, implica ainda que a altura do fuste será de13 vezes o raio.

• Seja a altura do capitel dividida em três partes, das quais uma formará oábaco com o seu cimáteo, o segundo o équino (coxim) com os seus aneis e oterceiro o pescoço.

Isto quer dizer que o ábaco tem uma altura de um terço de um mo-dulo, ou seja 1

3 do raio da base, e o coxim terá os restantes dois terços,ou seja, 2

3 do raio da base.

Estas considerações levam-nos a poder determinar o valor de algunsdos parâmetros de desenho das colunas dóricas em termos do raio da basedo fuste. Em termos de implementação, isso quer dizer que os parâmetrosda função passam a ser variáveis locais cuja atribuição é feita aplicandoas proporções estabelecidas por Vitrúvio ao parâmetro r-base-fuste. Adefinição da função fica então:

(defun coluna (pr-base-fuste r-base-coxim

117

Page 119: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 26: Variações de colunas dóricas segundo as proporções de Vitrúvio.

/ 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 função já é possível desenhar colunas que se aproximammais do padrão dórico (tal como estabelecido por Vitrúvio).41 A Figura 26apresenta as colunas desenhadas pelas seguintes invocações:

(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)

41A Ordem Dórica estabelece ainda mais uma relação entre os parâmetros das colunas,relação essa que só iremos implementar na secção 7.10.

118

Page 120: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

7.8 Selecção

As proporções de Vitrúvio permitiram-nos reduzir o número de parâme-tros independentes de uma coluna Dórica a apenas dois: o raio da basedo fuste e o raio da base do coxim. Contudo, não parece correcto que es-tes parâmetros sejam totalmente independentes pois isso permite construircolunas aberrantes em que o topo do fuste é mais largo do que a base, talcomo acontece com a coluna mais à direita na Figura 26.

Na verdade, a caracterização da Ordem Dórica que apresentámos encontra-se incompleta pois, acerca das proporções das colunas, Vitrúvio afirmouainda que:

. . . se uma coluna tem quinze pés ou menos, divida-se alargura na base em seis partes e usem-se cinco dessas partespara formar a largura no topo, . . . [Vitrúvio, Os Dez Livros daArquitectura, Livro III, Cap. 3.1]

Até agora, fomos capazes de traduzir todas as regras que fomos anun-ciando mas, desta vez, a tradução levanta-nos uma nova dificuldade: serápossível traduzir uma afirmação da forma “se, então” para Auto Lisp?

O termo “se, então” permite-nos executar uma acção dependendo deuma determinada condição ser verdadeira ou falsa: se uma coluna temquinze pés ou menos, então o topo da coluna tem 5

6 da base, caso contrário,. . . . Na linguagem Lisp, estes termos descrevem uma forma de actuaçãoque se denomina de estrutura de controle de selecção. A selecção permite-nos escolher uma via de acção mas apenas se uma determinada condiçãofor verdadeira.

A estrutura de controle de selecção é mais sofisticada que a sequenci-ação. Ela baseia-se na utilização de expressões condicionais para decidirqual a próxima expressão a avaliar. A forma mais simples desta estruturade controle é o if cuja sintaxe é a seguinte:

(if condicionalconsequentealternativa)

O valor de uma combinação cujo primeiro elemento é o if é obtido daseguinte forma:

1. A expressão condicional é avaliada.

2. Se o valor obtido da avaliação anterior é verdade, o valor da combi-nação é o valor da expressão consequente.

119

Page 121: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

3. Caso contrário, o valor obtido da avaliação anterior é falso e o valorda combinação é o valor da expressão alternativa.

Este comportamento pode ser confirmado pelos seguintes exemplos:

_$ (if (> 3 2)12)

1_$ (if (> 3 4)

12)

2

Usando o if podemos definir funções cujo comportamento dependede uma ou mais condições. Por exemplo, consideremos a função max querecebe dois números como argumentos e devolve o maior deles. Para de-finirmos esta função apenas precisamos de testar se o primeiro argumentoé maior que o segundo. Se for, a função devolve o primeiro argumento,caso contrário devolve o segundo. Com base neste raciocínio, podemosescrever:

(defun max (x y)(if (> x y)xy))

Muitas outras funções podem ser definidas à custa do if. Por exemplo,para calcularmos o valor absoluto de um número x, |x|, temos de saber seele é negativo. Se for, o seu valor absoluto é o seu simétrico, caso contrárioé ele próprio. Eis a definição:

(defun abs (x)(if (< x 0)(- x)x))

Um outro exemplo mais interessante ocorre com a função matemáticasinal sgn, também conhecida como função signum (“sinal,” em Latim). Estafunção pode ser vista como a função dual da função valor absoluto poistem-se sempre x = sgn(x)|x|. A função sinal é definida por

sgnx =

−1 se x < 00 se x = 01 caso contrário

120

Page 122: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Quando definimos esta função em Lisp notamos que é necessário em-pregar mais do que um if:

(defun signum (x)(if (< x 0)-1(if (= x 0)01)))

7.9 Selecção Múltipla—A Forma cond

Quando uma definição de função necessita de vários ifs encadeados, énormal que o código comece a ficar mais difícil de ler. Neste caso, é pre-ferível usar uma outra forma que torna a definição da função mais legível.Para evitar muitos ifs encadeados o Lisp providencia uma outra formadenominada cond cuja sintaxe é a seguinte:

(cond (expr0,0 expr0,1 ... expr0,n)(expr1,0 expr1,1 ... expr1,m)...(exprk,0 exprk,1 ... exprk,p))

O cond aceita qualquer número de argumentos. Cada argumento é de-nominado cláusula e é constituído por uma lista de expressões. A semânticado cond consiste em avaliar sequencialmente a primeira expressão expri,0de cada cláusula até encontrar uma cujo valor seja verdade. Nesse mo-mento, o cond avalia todas as restantes expressões dessa cláusula e devolveo valor da última. Se nenhuma das cláusulas tiver uma primeira expressãoque avalie para verdade, o cond devolve nil. Se a cláusula cuja primeiraexpressão é verdade não contiver mais expressões, o cond devolve o valordessa primeira expressão.

É importante perceber que os parêntesis que envolvem as cláusulas nãocorrespondem a nenhuma combinação: eles simplesmente fazem parte dasintaxe do cond e são necessários para separar as cláusulas umas das ou-tras.

A pragmática usual para a escrita de um cond (em especial quandocada cláusula contém apenas duas expressões) consiste em alinhar as ex-pressões umas debaixo das outras.

Usando o cond, a função sinal pode ser escrita de forma mais simples:

(defun signum (x)(cond ((< x 0)

121

Page 123: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

-1)((= x 0)0)

(t1)))

Note-se, no exemplo anterior, que a última cláusula do cond tem, comoexpressão lógica, o símbolo t. Como já vimos, este símbolo representa averdade pelo que a sua presença garante que ela será avaliada no caso denenhuma das cláusulas anteriores o ter sido. Neste sentido, cláusula daforma (t ...) representa um “em último caso . . . .”

Exercício 7.9.1 Qual o significado de (cond (expr1 expr2))?

Exercício 7.9.2 Qual o significado de (cond (expr1) (expr2))?

A forma cond não é estritamente necessária na linguagem pois é pos-sível fazer exactamente o mesmo com uma combinação entre formas ifencadeadas e formas progn, tal como a seguinte equivalência o demons-tra:

(cond (expr0,0 expr0,1 ... expr0,n)(expr1,0 expr1,1 ... expr1,m)...(exprk,0 exprk,1 ... exprk,p))

m

(if expr0,0

(prognexpr0,1 ... expr0,n)

(if expr1,0

(prognexpr1,1 ... expr1,m)...

(if exprk,0(prognexprk,1 ... exprk,p)

nil)))

Contudo, pragmaticamente falando, a forma cond pode simplificar subs-tancialmente o programa quando o número de if encadeados é maior queum ou dois ou quando se pretende usar sequenciação no consequente oualternativa do if.

122

Page 124: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Exercício 7.9.3 Defina uma função soma-maiores que recebe três números como argu-mento e determina a soma dos dois maiores.

Exercício 7.9.4 Defina a função max3 que recebe três números como argumento e calcula omaior entre eles.

Exercício 7.9.5 Defina a função segundo-maior que recebe três números como argumentoe devolve o segundo maior número, i.e., que está entre o maior e o menor.

7.10 Selecção nas Proporções de Vitrúvio

Uma vez compreendida a estrutura de controle de selecção, estamos emcondições de implementar a última regra de Vitrúvio sobre as proporçõesdas colunas da Ordem Dórica. A regra afirma que:

A diminuição no topo de uma coluna parece ser reguladasegundo os seguintes princípios: se uma coluna tem menos dequinze pés, divida-se a largura na base em seis partes e usem-secinco dessas partes para formar a largura no topo. Se a colunatem entre quinze e vinte pés, divida-se a largura na base emseis partes e meio e usem-se cinco e meio dessas partes para alargura no topo da coluna. Se a coluna tem entre vinte e trintapés, divida-se a largura na base em sete partes e faça-se o topodiminuido medir seis delas. Uma coluna de trinta a quarentapés deve ser dividida na base em sete partes e meia e, no prin-cípio da diminuição, deve ter seis partes e meia no topo. Co-lunas de quarenta a cinquenta pés devem ser divididas em oitopartes e diminuidas para sete delas no topo da coluna debaixodo capitel. No caso de colunas mais altas, determine-se pro-porcionalmente a diminuição com base nos mesmos princípios.[Vitrúvio, Os Dez Livros da Arquitectura, Livro III, Cap. 3.1]

Estas considerações de Vitrúvio permitem-nos determinar a razão entreo topo e a base de uma coluna em função da sua altura em pés.42

Consideremos então a definição de uma função, que iremos denominarde raio-topo-fuste, que recebe como parâmetros a largura da base da

42O pé foi a unidade fundamental de medida durante inúmeros séculos mas a sua realdimensão variou ao longo do tempo. O comprimento do pé internacional é de 304.8 mi-límetros e foi estabelecido por acordo em 1958. Antes disso, vários outros comprimentosforam usados, como o pé Dórico de 324 milímetros, os pés Jónico e Romano de 296 milíme-tros, o pé Ateniense de 315 milímetros, os pés Egípcio e Fenício de 300 milímetros, etc.

123

Page 125: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

coluna e a altura da coluna e devolve como resultado a largura do topo dacoluna.

Uma tradução literal das considerações de Vitrúvio para Lisp permite-nos começar por escrever:

(defun raio-topo-fuste (raio-base altura)(cond ((< altura 15) (* (/ 5.0 6.0) raio-base))

...))

O fragmento anterior corresponde, obviamente, à afirmação: se uma co-luna tem menos de quinze pés, divida-se a largura na base em seis partes e usem-secinco dessas partes para formar a largura no topo. No caso de a coluna não termenos de quinze pés, então passamos ao caso seguinte: se a coluna tem entrequinze e vinte pés, divida-se a largura na base em seis partes e meio e usem-se cincoe meio dessas partes para a largura no topo da coluna. A tradução deste segundocaso 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 análise cuidadosa das duas cláusulas anteriores mostra que, narealidade, estamos a fazer testes a mais na segunda cláusula. De facto, seconseguimos chegar à segunda cláusula é porque a primeira é falsa, i.e., aaltura não é menor que 15 e, portanto, é maior ou igual a 15. Nesse caso,é inútil estar a testar novamente se a altura é maior ou igual a 15. Assim,podemos simplificar a função 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 continuação da tradução levar-nos-á, então, 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))...))

124

Page 126: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

O problema agora é que Vitrúvio deixou a porta aberta para colunasarbitrariamente altas, dizendo simplesmente que no caso de colunas mais al-tas, determine-se proporcionalmente a diminuição com base nos mesmos princípios.Para percebermos claramente de que princípios estamos a falar, considere-mos a evolução da relação entre o topo e a base das colunas que é visívelna imagem lateral.

0

56

15

5 12

6 12

20

67

30

6 12

7 12

40

78

50

A razão entre o raio do topo da coluna e o raio da base da colunaé, tal como se pode ver na margem (e já era possível deduzir da funçãoraio-topo-fuste), uma sucessão da forma

56,

512

612

,67,

612

712

,78, · · ·

Torna-se agora óbvio que, para colunas mais altas, “os mesmos princí-pios” de que Vitrúvio fala se resumem a, para cada 10 pés adicionais, somar12 quer ao numerador, quer ao denominador. No entanto, é importante re-parar que este princípio só pode ser aplicado a partir dos 15 pés de alturapois o primeiro intervalo é maior que os restantes. Assim, temos de tra-tar de forma diferente as colunas até aos 15 pés e, daí para a frente, bastasubtrair 20 pés à altura e determinar a divisão inteira por 10 para saber onúmero de vezes que precisamos de somar 1

2 quer ao numerador quer aodenominador de 6

7 .É este “tratar de forma diferente” um caso e outro que, mais uma vez,

sugere a necessidade de utilização de uma estrutura de controle de selec-ção: é necessário distinguir dois casos e reagir em conformidade para cadaum. No caso da coluna de Vitrúvio, se a coluna tem uma altura a até 15pés, a razão entre o topo e a base é r = 5

6 ; se a altura a não é inferior a 15pés, a razão r entre o topo e a base será:

r =6 + ba−20

10 c ·12

7 + ba−2010 c ·

12

A título de exemplo, consideremos uma coluna com 43 pés de altura. Adivisão inteira de 43 − 20 por 10 é 2 portanto temos de somar 2 · 1

2 = 1 aonumerador e denominador de 6

7 , obtendo 78 = 0.875.

Para um segundo exemplo nos limites do absurdo, consideremos umacoluna da altura do Empire State Building, i.e., com 449 metros de altura.Um pé, na ordem Dórica, media 324 milímetros pelo que em 449 metrosexistem 449/0.324 ≈ 1386 pés. A divisão inteira de 1386 − 20 por 10 é136. A razão entre o topo e a base desta hipotética coluna será então de

125

Page 127: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

6+136/27+136/2 = 74

75 = 0.987. Este valor, por ser muito próximo da unidade, mostraque a coluna seria praticamente cilíndrica.

Com base nestas considerações, podemos agora definir uma funçãoque, dado um número inteiro representando a altura da coluna em pés,calcula a razão entre o topo e a base da coluna. Antes, contudo, convémsimplificar a fórmula para as colunas com altura não inferior a 15 pés. As-sim,

r =6 + ba−20

10 c ·12

7 + ba−2010 c ·

12

=12 + ba−20

10 c14 + ba−20

10 c=

12 + b a10c − 214 + b a10c − 2

=10 + b a10c12 + b a10c

A definição da função fica então:

(defun raio-topo-fuste (raio-base altura / divisoes)(setq divisoes (fix (/ altura 10)))(if (< altura 15)(* (/ 5.0 6.0)

raio-base)(* (/ (+ 10.0 divisoes)

(+ 12.0 divisoes))raio-base)))

Esta é a última relação que nos falta para especificarmos completamenteo desenho de uma coluna dórica de acordo com as proporções referidaspor Vitrúvio no seu tratado de arquitectura. Vamos considerar, para estedesenho, que vamos fornecer as coordenadas do centro da base da colunae a sua altura. Todos os restantes parâmetros serão calculados em termosdestes. Eis a definição da função:

(defun coluna-dorica (p altura /a-fuste r-base-fustea-coxim r-base-coxima-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 utilização da função produz a sequência de co-lunas apresentadas na Figura 27:43

43Note-se que, agora, a altura da coluna tem de ser especificada em pés dóricos.

126

Page 128: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 27: Variações de colunas dóricas segundo as proporções de Vitrúvio.

(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)

Exercício 7.10.1 A função raio-topo-fuste calcula o valor da variável local divisoesmesmo quando o parâmetro altura é menor ou igual a 15. Redefina a função de modo aque a variável divisoes só seja definida valor quando o seu valor é realmente necessário.

7.11 Operações com Coordenadas

Vimos, na secção 4.1, a definição e implementação de um tipo abstractopara coordenadas bi-dimensionais que assentava nas seguinte funções:

127

Page 129: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(defun xy (x y)(list x y))

(defun cx (c)(car c))

(defun cy (c)(cadr c))

Vimos também, na secção 4.6 que é possível definir as coordenadas tri-dimensionais como uma generalização óbvia do tipo anterior. Para isso,bastou-nos preservar as posições das coordenadas bi-dimensionais x e y narepresentação de coordenadas tri-dimensionais, o que implica colocarmosa coordenada z a seguir às outras duas. Isto levou-nos a definir o construtorde coordenadas Cartesianas tri-dimensionais xyz com a seguinte forma:

(defun xyz (x y z)(list x y z))

O correspondente selector da coordenada z ficou então definido como:

(defun cz (c)(caddr c))

Uma vez que adoptámos uma representação de coordenadas tri-dimensionaisque é uma extensão da representação correspondente para coordenadasbi-dimensionais, os selectores cx e cy que eram válidos para coordena-das bi-dimensionais passaram a ser válidos também para coordenadas tri-dimensionais. Infelizmente, o inverso já não é necessariamente verdade:o selector cz não pode ser aplicado a coordenadas bi-dimensionais poisestas não possuem, na sua representação, esta terceira coordenada. No en-tanto, é possível generalizar este selector de modo a torná-lo aplicável tam-bém a coordenadas bi-dimensionais, simplesmente assumindo que o casobi-dimensional se desenrola no plano z = 0, i.e., assumindo que (x, y) =(x, y, 0). Em termos de implementação, para que o selector cz seja compatí-vel com coordenadas bi- ou tri-dimensionais, ele precisa de saber distinguiras duas representações. Uma vez que uma das representações é uma listade dois elementos e a outra é uma lista de três elementos, o mais simples étestar se existe algo para lá do segundo elemento, i.e., se o resto do resto dalista não está vazia. Como vimos na secção 6.10, a função null reconhece alista vazia, o que nos permite definir um reconhecedor diferente para cadatipo de coordenada:

128

Page 130: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(defun xy? (c)(null (cddr c)))

(defun xyz? (c)(not (null (cddr c))))

Usando estas funções é agora mais simples definir correctamente o se-lector cz: para coordenadas bi-dimensionais, devolve zero. Para coordena-das 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 paradecidir o que devolver. Este teste e escolha do caminho a seguir é a marcada estrutura de controle de selecção.

A redefinição do selector cz para lidar com os dois tipos de coordena-das tem a vantagem adicional de permitir que outras funções de coorde-nadas tri-dimensionais se possam aplicar a coordenadas bi-dimensionais.Por exemplo, a seguinte função de coordenadas tri-dimensionais, definidana secção 4.5,

(defun +xyz (p dx dy dz)(xyz (+ (cx p) dx)

(+ (cy p) dy)(+ (cz p) dz)))

passa a ser directamente aplicável a coordenadas bi-dimensionais sem qual-quer tipo de alteração.

Infelizmente, nem todas as funções conseguem funcionar inalteradas.Por exemplo, consideremos a função +xy que permitia deslocar coordena-das bi-dimensionais:

(defun +xy (c x y)(xy (+ (cx c) x)

(+ (cy c) y)))

Como é óbvio pela análise da função anterior, se ela for aplicada a umacoordenada tri-dimensional, perde-se a coordenada z, o que é manifesta-mente indesejável. Para evitar este problema e, ao mesmo tempo, preservara compatibilidade com o caso bi-dimensional, temos de distinguir os doiscasos:

129

Page 131: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(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 além da função +xy também usámos anteriormente a função +polque somava a um ponto uma “distância” especificada em termos de coor-denadas polares:

(defun +pol (c ro fi)(+xy c

(* ro (cos fi))(* ro (sin fi))))

Uma vez que a função +pol está definida em termos da função +xye esta já sabe tratar coordenadas tri-dimensionais, também +pol saberátratar coordenadas tri-dimensionais e, consequentemente, não precisa deser redefinida. O mesmo se pode dizer das funções +x e +y que apenasdependem de +xy.

Finalmente, consideremos a definição da função +c que apresentámosna secção 4.11 e que se destinava a deslocar um ponto ao longo de umvector (especificado pelas coordenadas da sua extremidade):

(defun +c (p0 p1)(xy (+ (cx p0) (cx p1))

(+ (cy p0) (cy p1))))

É evidente pela definição da função que ela não é aplicável ao casotri-dimensional pois só lida com as coordenadas x e y de ambos os pon-tos. Para lidar correctamente com o caso tri-dimensional teremos de ter emconta que qualquer um dos parâmetros pode corresponder a um ponto emcoordenadas tri-dimensionais e que será apenas quando ambos os parâme-tros forem coordenadas bi-dimensionais que poderemos usar a definiçãoanterior. Assim, temos:

130

Page 132: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(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 além da “soma” de um vector a um ponto é por vezes útil con-siderar a operação inversa, que “subtrai” um vector a um ponto, i.e., quedetermina a origem do vector cujo destino é o ponto dado ou, equivalente-mente, as projecções do vector que liga os dois pontos dados. Por analogiacom a operação +c, vamos denominar esta operação de -c e a sua definiçãoserá, 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)))))

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)

131

Page 133: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Pode ser também útil poder multiplicar uma coordenada por um fac-tor, correspondendo a uma simples homotetia. Mais uma vez, temos dedistinguir 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 definições anteriores, a estrutura de controle deselecção é fundamental para se poder obter os diferentes comportamentosnecessários para tratar o caso de coordenadas Cartesianas bi-dimensionaisou tri-dimensionais.

Finalmente, para além das operações de adição e subtracção de coor-denadas, pode ser útil uma operação de comparação de coordenadas quedesignaremos por =c. Duas coordenadas serão iguais se as suas compo-nentes 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 função anterior funciona igualmente bem com coordenadas bi-dimensionais,tri-dimensionais ou mistas pois elas só poderão diferir na presença, ou não,da coordenada z mas o selector cz encarrega-se de esconder essa diferença.

O conjunto de funções que descrevemos atrás e que inclui os construto-res xy, +xy, xyz, +xyz, +x, +y, +z, +c, -c e *c, os selectores cx, cy e cz,os reconhecedores xy? e xyz? e, finalmente, o teste =c constituem um tipoabstracto para coordenadas Cartesianas que iremos frequentemente usarde futuro.

Para além das coordenadas Cartesianas, é ainda usual empregarem-sedois outros sistemas de coordenadas que iremos ver de seguida: as coorde-nadas cilíndricas e as coordenadas esféricas.

7.12 Coordenadas Cilíndricas

Tal como podemos verificar na Figura 28, um ponto, em coordenadas cilín-dricas, 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. É fácil de ver que o raio e

132

Page 134: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

y

z

x

P

z

ρ

φ

Figura 28: Coordenadas cilíndricas.

o ângulo correspondem às coordenadas polares da projecção do ponto noplano z = 0.

Dado um ponto (ρ, φ, z) em coordenadas cilíndricas, o mesmo pontoem coordenadas Cartesianas é

(ρ cosφ, ρ sinφ, z)

De igual modo, dado um ponto (x, y, z) em coordenadas Cartesianas, omesmo ponto em coordenadas cilíndricas é

(√x2 + y2, atan

y

x, z)

Estas equivalências permitem-nos definir uma função que constrói pon-tos em coordenadas cilíndricas empregando as coordenadas Cartesianascomo representação canónica:

(defun cil (ro fi z)(xyz (* ro (cos fi))

(* ro (sin fi))z))

No caso de pretendermos simplesmente somar a um ponto um vectorem coordenadas cilíndricas, podemos tirar partido da função +c e definir:

133

Page 135: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(defun +cil (p ro fi z)(+c p (cil ro fi z)))

Exercício 7.12.1 Defina os selectores cil-ro, cil-fi e cil-z que devolvem, respectiva-mente, os componentes ρ, φ e z de um ponto construído pelo construtor cil.

Existem inúmeras curvas, superfícies e volumes que são mais simples-mente descritos usando coordenadas cilíndricas do que usando coordena-das rectangulares. Por exemplo, a equação paramétrica de uma hélice, emcoordenadas cilíndricas, é trivial:

(ρ, φ, z) = (1, t, t)

No entanto, em coordenadas rectangulares, somos obrigados a empregaralguma trigonometria para obter a equação equivalente:

(x, y, z) = (cos t, sin t, t)

Exercício 7.12.2 Defina uma função escadas capaz de construir uma escada em hélice. Aimagem seguinte mostra três exemplos destas escadas.

Como se pode ver pela imagem anterior, a escada é constituída por um cilindro centralno qual se apoiam 10 degraus cilíndricos. Para facilitar a experimentação considere que ocilindro central é de raio r. Os degraus são iguais ao cilindro central, possuem 10 raios decomprimento e estão dispostos a alturas progressivamente crescentes. Cada degrau estáa uma altura h em relação ao degrau anterior e, visto em planta, faz um ângulo α com odegrau anterior.

A função escada deverá receber as coordenadas do centro da base do cilindro central,o raio r, a altura h e o ânguloα. A título de exemplo, considere que as três escadas anterioresforam construídas pelas seguintes invocações:

(escada (xyz 0 0 0) 1.0 3 (/ pi 6))(escada (xyz 0 40 0) 1.5 5 (/ pi 9))(escada (xyz 0 80 0) 0.5 6 (/ pi 8))

134

Page 136: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

y

z

x

P

ψ ρ

φ

Figura 29: Coordenadas Esféricas

7.13 Coordenadas Esféricas

Tal como podemos ver na Figura 29, um ponto, em coordenadas esféricas(também denominadas polares), caracteriza-se pelo comprimento ρ do raiovector, por um ângulo φ (denominado longitude ou azimute) que a projecçãodesse vector no plano z = 0 faz com o eixo x e por ângulo ψ (denominadocolatitude44, zénite ou ângulo polar) que o vector faz com o eixo z.

Dado um ponto (ρ, φ, ψ) em coordenadas esféricas, o mesmo ponto emcoordenadas Cartesianas é

(ρ sinψ cosφ, ρ sinψ sinφ, ρ cosψ)

De igual modo, dado um ponto (x, y, z) em coordenadas Cartesianas, omesmo ponto em coordenadas esféricas é

(√x2 + y2 + z2, atan

y

x, atan

√x2 + y2

z)

Tal como fizemos para as coordenadas cilíndricas, vamos definir o cons-trutor de coordenadas esféricas e a soma de um ponto a um vector em co-ordenadas esféricas:

44A colatitude é, como é óbvio, o ângulo complementar à latitude, i.e., a diferença entreo pólo (π

2) e a latitude.

135

Page 137: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(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)))

Exercício 7.13.1 Defina os selectores esf-ro, esf-fi e esf-psi que devolvem, respecti-vamente, os componentes ρ, φ e ψ de um ponto construído pelo construtor esf.

7.14 Recursão

Vimos que as nossas funções, para fazerem algo útil, precisam de invocaroutras funções. Por exemplo, se já tivermos a função que calcula o qua-drado de um número e pretendermos definir a função que calcula o cubode um número, podemos facilmente fazê-lo à custa do quadrado e de umamultiplicação adicional, i.e.:

(defun cubo (x)(* (quadrado x) x))

Do mesmo modo, podemos definir a função quarta-potencia à custado cubo e de uma multiplicação adicional, i.e.:

(defun quarta-potencia (x)(* (cubo x) x))

Como é óbvio, podemos continuar a definir sucessivamente novas fun-ções para calcular potências crescentes mas isso não só é moroso como serásempre limitado. Seria muito mais útil podermos generalizar o processoe definir simplesmente a função potência que, a partir de dois números (abase e o expoente) calcula o primeiro elevado ao segundo.

No entanto, aquilo que fizemos para a quarta-potencia, o cubo eo quadrado dão-nos uma pista muito importante: se tivermos uma funçãoque calcula a potência de expoente imediatamente inferior, então basta-nos umamultiplicação adicional para calcular a potência seguinte.

Dito de outra forma, temos:

(defun potencia (x n)(* (potencia-inferior x n) x))

Embora tenhamos conseguido simplificar o problema do cálculo de po-tência, sobrou uma questão por responder: como podemos calcular a po-tência imediatamente inferior? A resposta poderá não ser óbvia mas, uma

136

Page 138: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

vez percebida, é trivial: a potência imediatamente inferior à potência de expoenten é a potência de expoente (n−1). Isto implica que (potencia-inferior x n)é exactamente o mesmo que (potencia x (- n 1)). Com base nestaideia, podemos reescrever a definição anterior:

(defun potencia (x n)(* (potencia x (- n 1)) x))

Apesar da nossa solução engenhosa, esta definição tem um problema:qualquer que seja a potência que tentemos calcular, nunca conseguiremosobter o resultado final. Para percebermos este problema, é mais simplesusar um caso real: tentemos calcular a terceira potência do número 4, i.e.,(potencia 4 3).

Para isso, de acordo com a definição da função potencia, será precisoavaliar a expressão(* (potencia 4 2) 4)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 . . .

É fácil vermos que este processo nunca mais termina. O problema estáno facto de termos reduzido o cálculo da potência de um número elevadoa um expoente ao cálculo da potência desse número elevado ao expoenteimediatamente inferior mas não dissemos em que situação é que já temosum expoente suficientemente simples cuja solução seja imediata. Quais sãoas situações em que isso acontece? Já vimos que quando o expoente é 2, afunção quadrado devolve o resultado correcto, pelo que o caso n = 2 éjá suficientemente simples. No entanto, é possível ter um caso ainda maissimples: quando o expoente é 1, o resultado é simplesmente a base. Fi-nalmente, o caso mais simples de todos: quando o expoente é zero, o re-sultado é 1, independentemente da base. Este último caso é fácil de perce-ber quando vemos que a avaliação de (potencia 4 2) (i.e., do quadradode quatro) se reduz, em última análise, a (* (* (potencia 4 0) 4) 4).

137

Page 139: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Para que esta expressão seja equivalente a (* 4 4) é necessário que (potencia 4 0)seja 1.

Estamos então em condições de definir correctamente a função potencia:

1. Quando o expoente é zero, o resultado é um.

2. Caso contrário, calculamos a potência de expoente imediatamente in-ferior e multiplicamo-la pela base.

(defun potencia (x n)(if (zerop n)1(* (potencia x (- n 1)) x)))

A função anterior é um exemplo de uma função recursiva, i.e., uma fun-ção que está definida em termos de si própria. Dito de outra forma, umafunção recursiva é uma função que se usa a si própria na sua definição. Esseuso é óbvio quando “desenrolamos” a avaliação de (potencia 4 3):

(potencia 4 3)↓

(* (potencia 4 2) 4)↓

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

(* (* (* (potencia 4 0) 4) 4) 4)↓

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

(* (* 4 4) 4)↓

(* 16 4)↓64

A recursão é a estrutura de controle que permite que uma função sepossa invocar a si própria durante a sua própria avaliação. A recursão éuma das mais importantes ferramentas de programação pelo que é funda-mental que a percebamos bem. Muitos problemas aparentemente comple-xos possuem soluções recursivas extraordinariamente simples.

Existem inúmeros exemplos de funções recursivas. Uma das mais sim-ples é a função factorial que se define matematicamente como:

138

Page 140: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

n! =

{1, se n = 0n · (n− 1)!, caso contrário.

A tradução desta fórmula para Lisp é directa:

(defun factorial (n)(if (zerop n)

1(* n (factorial (- n 1)))))

É importante repararmos que em todas as funções recursivas existe:

• Um caso básico (também chamado caso de paragem) cujo resultado éimediatamente conhecido.

• Um caso não básico (também chamado caso recursivo) em que se trans-forma o problema original num sub-problema mais simples.

Se analisarmos a função factorial, o caso básico é o teste de igualdade azero (zerop n), o resultado imediato é 1, e o caso recursivo é, obviamente,(* n (factorial (- n 1))).

Geralmente, uma função recursiva só está correcta se tiver uma expres-são condicional que identifique o caso básico, mas não é obrigatório queassim seja. A invocação de uma função recursiva consiste em ir resolvendosubproblemas sucessivamente mais simples até se atingir o caso mais sim-ples de todos, cujo resultado é imediato. Desta forma, o padrão mais co-mum para escrever uma função recursiva é:

• Começar por testar os casos básicos.

• Fazer uma invocação recursiva com um subproblema cada vez maispróximo de um caso básico.

• Usar o resultado da invocação recursiva para produzir o resultado dainvocação original.

Dado este padrão, os erros mais comuns associados às funções recursi-vas são, naturalmente:

• Não detectar um caso básico.

• A recursão não diminuir a complexidade do problema, i.e., não pas-sar para um problema mais simples.

139

Page 141: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

• Não usar correctamente o resultado da recursão para produzir o re-sultado originalmente pretendido.

Repare-se que uma função recursiva que funciona perfeitamente paraos casos para que foi prevista pode estar completamente errada para outroscasos. A função factorial é um exemplo: quando o argumento é nega-tivo, o problema torna-se cada vez mais complexo, cada vez mais longe docaso 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 função recursiva é a recursão nuncaparar, ou porque não se detecta correctamente o caso básico ou por a re-cursão não diminuir a complexidade do problema. Neste caso, o númerode invocações recursivas cresce indefinidamente até esgotar a memória docomputador, altura em que o programa gera um erro. No caso do AutoLisp, esse erro não é inteiramente óbvio pois o avaliador apenas interrompea avaliação sem apresentar qualquer resultado. Eis um exemplo:

_$ (factorial 3)6_$ (factorial -1)_$

É muito importante compreendermos bem o conceito de recursão. Em-bora a princípio possa ser difícil abarcar por completo as implicações desteconceito, a recursão permite resolver, com enorme simplicidade, problemasaparentemente muito complexos.

Como iremos ver, também em arquitectura a recursão é um conceitofundamental.

140

Page 142: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Exercício 7.14.1 A função de Ackermann é definida para números não negativos da se-guinte forma:

A(m,n) =

8><>:n+ 1 se m = 0

A(m− 1, 1) se m > 0 e n = 0

A(m− 1, A(m,n− 1)) se m > 0 e n > 0

Defina, em Lisp, a função de Ackermann.

Exercício 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)

Exercício 7.14.3 Defina uma função denominada escada que, dado um ponto P , um nú-mero de degraus, o comprimento do espelho e e o comprimento do cobertor c de cadadegrau, desenha a escada em AutoCad com o primeiro espelho a começar a partir do pontodado, tal como se vê na imagem seguinte:

c

e

P

Exercício 7.14.4 Defina uma função equilibrio-circulos capaz de criar qualquer umadas figuras apresentadas em seguida:

141

Page 143: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Note que os círculos possuem raios que estão em progressão geométrica de razão f ,com 0 < f < 1. Assim, cada círculo (excepto o primeiro) tem um raio que é o produto de fpelo raio do círculo maior em que está apoiado. O círculo mais pequeno de todos tem raiomaior ou igual a 1. A sua função deverá ter como parâmetros o centro e o raio do círculomaior e ainda o factor de redução f .

Exercício 7.14.5 Considere o desenho de círculos em torno de um centro, tal como apresen-tado na seguinte imagem:

x

y

p

r0

r1

φ

∆φ

Escreva uma função denominada circulos-concentricos que, a partir das coor-denadas p do centro de rotação, do número de círculos n, do raio de translacção r0, do raiode circunferência r1, do ângulo inicial φ e do incremento de ângulo ∆φ, desenha os círculostal como apresentados na figura anterior.

Teste a sua função com os seguintes expressões:

(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 avaliação deverá gerar a imagem seguinte:

Exercício 7.14.6 Considere o desenho de flores simbólicas compostas por um círculo inte-rior em torno da qual estão dispostos círculos concêntricos correspondentes a pétalas. Estescírculos deverão ser tangentes uns aos outros e ao círculo interior, tal como se apresenta naseguinte imagem:

142

Page 144: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Defina a função flor que recebe apenas o ponto correspondente ao centro da flor, oraio do círculo interior e o número de pétalas.

Teste a sua função com as expressões

(flor (xy 0 0) 5 10)(flor (xy 18 0) 2 10)(flor (xy 40 0) 10 20)

que deverão gerar a imagem seguinte:

7.15 Depuração de Programas Recursivos

Vimos, na secção 4.19 que os erros de um programa se podem classificar emtermos de erros sintáticos ou erros semânticos. Os erros sintáticos ocorremquando escrevemos frases inválidas na linguagem. Como exemplo de errosintático, consideremos a seguinte definição da função potencia onde nosesquecemos da lista de parâmetros:

143

Page 145: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(defun potencia(if (= n 0)1(* (potencia x (- n 1)) x)))

Este esquecimento é o suficiente para baralhar o Auto Lisp: ele esperavaencontrar a lista de parâmetros imediatamente a seguir a nome da funçãoe que, no lugar dela, encontra uma lista que começa com o símbolo if. Istofaz com que o Auto Lisp erradamente acredite que o símbolo if é o nomedo primeiro parâmetro e, daí para a frente, a sua confusão só aumenta. Adado momento, quando o Auto Lisp deixa, por completo, de compreenderaquilo que se pretendia definir, apresenta-nos um erro.

Os erros semânticos são mais complexos que os sintáticos pois, em ge-ral, só podem ser detectados durante a execução do programa.45 Por exem-plo, se tentarmos calcular o factorial de uma string iremos ter um erro, talcomo o seguinte exemplo mostra:

_$ (factorial 5)120_$ (factorial "cinco"); error: bad argument type: numberp: "cinco"

Este último erro, como é óbvio, não tem a ver com a regras da gramáticado Lisp: a “frase” da invocação da função factorial está correcta. Oproblema está no facto de não fazer sentido calcular o factorial de umastring pois o cálculo do factorial envolve operações aritméticas e estas nãosão aplicáveis a strings. Assim sendo, o erro tem a ver com o significadoda “frase” escrita, i.e., com a semântica. Trata-se, portanto, de um errosemântico.

A recursão infinita é outro exemplo de um erro semântico. Vimos que afunção factorial só pode ser invocada com um argumento não negativo ouprovoca recursão infinita. Consequentemente, se usarmos um argumentonegativo estaremos a cometer um erro semântico.

7.15.1 Trace

Vimos, na secção4.19, que o Visual Lisp disponibiliza vários mecanismospara fazermos a detecção de erros. Um dos mais simples é a forma traceque permite visualizar as invocações das funções. A forma trace recebe o

45Há casos de erros semânticos que podem ser detectados antes da execução do programamas essa detecção depende muito da qualidade da implementação da linguagem e da suacapacidade em antecipar as consequências dos programas.

144

Page 146: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

nome das funções cuja invocação se pretende analisar e altera essas funçõesde forma a que elas escrevam as sucessivas invocações com os respectivosargumentos, bem como o resultado da invocação. Se o ambiente do VisualLisp estiver activo, a escrita é feita numa janela especial do ambiente doVisual Lisp denominada Trace,46 caso contrário, é feita na janela de co-mandos do AutoCad. A informação apresentada em resultado do trace é,em geral, extremamente útil para a depuração das funções.

Por exemplo, para visualizarmos uma invocação da função factorial,consideremos a seguinte interacção:

_$ (trace factorial)FACTORIAL_$ (factorial 5)120

Em seguida, se consultarmos o conteúdo da janela de Trace, encontra-mos:

Entering (FACTORIAL 5)Entering (FACTORIAL 4)Entering (FACTORIAL 3)Entering (FACTORIAL 2)Entering (FACTORIAL 1)Entering (FACTORIAL 0)Result: 1

Result: 1Result: 2

Result: 6Result: 24

Result: 120

Note-se, no texto anterior escrito em consequência do trace, que a in-vocação que fizemos da função factorial aparece encostada à esquerda.Cada invocação recursiva aparece ligeiramente para a direita, permitindoassim visualizar a “profundidade” da recursão, i.e., o número de invoca-ções recursivas. O resultado devolvido por cada invocação aparece ali-nhado na mesma coluna dessa invocação.

É de salientar que a janela de Trace não tem dimensão infinita, peloque as recursões excessivamente profundas acabarão por não caber na ja-nela. Neste caso, o Visual Lisp reposiciona a escrita na coluna esquerdamas indica numericamente o nível de profundidade em que se encontra.Por exemplo, para o (factorial 15), aparece:

46Para se visualizar a janela de Trace basta seleccioná-la a partir do menu Window doAuto Lisp.

145

Page 147: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

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: 720Result: 5040

Result: 40320Result: 362880

Result: 3628800Result: 39916800

Result: 479001600Result: 1932053504

Result: 1278945280Result: 2004310016

No caso de recursões infinitas, apenas são mostradas as últimas invoca-ções realizadas antes de ser gerado o erro. Por exemplo, para (factorial -1),teremos:

...[19215] Entering (FACTORIAL -19216)[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)

146

Page 148: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

...[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 depuração de uma função, usa-se a forma especial untrace,que recebe o nome da função ou funções que se pretende retirar do trace.

Exercício 7.15.1 Faça o trace da função potência. Qual é o trace resultante da avaliação(potencia 2 10)?

Exercício 7.15.2 Defina uma função circulos capaz de criar a figura apresentada em se-guida:

Note que os círculos possuem raios que estão em progressão geométrica de razão 12

.Dito de outra forma, os círculos mais pequenos têm metade do raio do círculo maior quelhes é adjacente. Os círculos mais pequenos de todos têm raio maior ou igual a 1. A suafunção deverá ter como parâmetros apenas o centro e o raio do círculo maior.

Exercício 7.15.3 Defina uma função denominada serra que, dado um ponto P , um nú-mero de dentes, o comprimento c de cada dente e a altura a de cada dente, desenha umaserra em AutoCad com o primeiro dente a começar a partir do ponto P , tal como se vê naimagem seguinte:

147

Page 149: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

c

a

P

Exercício 7.15.4 Defina uma função losangulos capaz de criar a figura apresentada emseguida:

Note que os losângulos possuem dimensões que estão em progressão geométrica derazão 1

2. Dito de outra forma, os losângulos mais pequenos têm metade do tamanho do

losângulo maior em cujas extremidades estão centrados. Os losângulos mais pequenos detodos têm largura maior ou igual a 1. A sua função deverá ter como parâmetros apenas ocentro e a largura do losângulo maior.

7.16 Templos Dóricos

Vimos, pelas descrições de Vitrúvio, que os Gregos criaram um elaboradosistema de proporções para colunas. Estas colunas eram usadas para acriação de pórticos, em que uma sucessão de colunas encimadas por umtelhado servia de entrada para os edifícios e, em particular, para os tem-plos. Quando esse arranjo de colunas era avançado em relação ao edifício,denominava-se o mesmo de próstilo, classificando-se este pelo número decolunas que possuem em Distilo, Tristilo, Tetrastilo, Pentastilo, Hexastilo,etc. Quando o próstilo se alargava a todo o edifício, colocando colunas atoda a sua volta, denominava-se de peristilo.

Para além de descrever as proporções das colunas, Vitrúvio tambémexplicou no seu famoso tratado as regras que se deviam seguir para a sepa-ração entre colunas, distinguindo vários casos de templos, desde aquelesem que o espaço entre colunas era muito reduzido (picnostilo) até aos tem-plos com espaçamento excessivamente alargado (araeostilo), passando peloseu favorito (eustilo) em que o espaço entre colunas é variável, sendo maiornas colunas centrais.

148

Page 150: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Na prática, nem sempre as regras propostas por Vitrúvio representa-vam a realidade dos templos e, frequentemente, a distancia intercolunarvaria, sendo mais reduzida nas extremidades para dar um aspecto maisrobusto ao templo.

Para simplificar a nossa implementação, vamos ignorar estes detalhese, ao invés de distinguir vários stilo, vamos simplesmente usar como pa-râmetros as coordenadas da base do eixo da primeira coluna, a altura dacoluna, a separação entre os eixos das colunas47 (em termos de um “vec-tor” de deslocação entre colunas) e, finalmente, o número de colunas quepretendemos colocar. O “vector” de deslocação entre colunas destina-se apermitir orientar as colunas em qualquer direcção e não só ao longo do eixodos x ou y.

O raciocínio para a definição desta função é, mais uma vez, recursivo:

• Se o número de colunas a colocar for zero, então não é preciso fazernada e podemos simplesmente retornar nil.

• Caso contrário, colocamos uma coluna na coordenada indicada e, re-cursivamente, colocamos as restantes colunas a partir da coordenadaque resulta de aplicarmos o “vector” de deslocação à coordenada ac-tual. Como são duas acções que queremos realizar sequencialmente,teremos de usar o operador progn para as agrupar numa acção con-junta.

Traduzindo este raciocínio para Lisp, temos:

(defun colunas-doricas (p altura separacao colunas)(if (= colunas 0)nil(progn(coluna-dorica p altura)(colunas-doricas (+c p separacao)

alturaseparacao(- colunas 1)))))

Finalmente, podemos testar a criação das colunas usando, por exemplo:

(colunas-doricas (xy 0 0) 10 (xy 5 0) 8)

cujo resultado está apresentado na Figura 30:

47A denominada distância interaxial, por oposição à distância intercolunar que mede oespaço aberto entre colunas adjacentes.

149

Page 151: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 30: Uma perspectiva de um conjunto de oito colunas dóricas com 10unidades de altura e 5 unidades de separação entre os eixos da colunas aolongo do eixo x.

150

Page 152: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

A partir do momento em que sabemos construir uma fileira de colu-nas torna-se relativamente fácil a construção das quatro fileiras necessáriaspara os templos em peristilo. Normalmente, a descrição destes templosfaz-se em termos do número de colunas da fronte e do número de colunasdo lado, mas assumindo que as colunas dos cantos contam para ambas asmedidas. Isto quer dizer que num templo de, por exemplo, 6× 12 colunasexistem, na realidade, apenas 4× 2 + 10× 2 + 4 = 32 colunas. Para a cons-trução do peristilo, para além do número de colunas das frontes e lados,será necessário conhecer a distância entre colunas nas frontes e nos lados e,claro, a altura das colunas.

Em termos de algoritmo, vamos começar por construir as frontes, dese-nhando todas as colunas incluindo os cantos. Em seguida construímos oslados, tendo em conta que os cantos já foram colocados. Para simplificar,vamos considerar que o templo tem as frontes paralelas ao eixo x (e os la-dos paralelos ao eixo y) e que a primeira coluna é colocada num ponto Pdado como primeiro parâmetro. Assim, temos:

(defun peristilo-dorico (pn-fronte n-ladod-fronte d-ladoaltura)

(colunas-doricas paltura (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 quese encontra representado da Figura 12. Este templo é do tipo peristilo, com-posto por 6 colunas (i.e., Hexastilo) em cada fronte e 14 colunas nos lados,num total de 36 colunas de 9 metros de altura. A distância entre os eixosdas colunas é de aproximadamente 4.8 metros nas frontes e de 4.6 nos la-dos. A expressão que cria o peristilo deste templo é, então:

(peristilo-dorico (xy 0 0) 6 14 4.8 4.6 9)

O resultado da avaliação da expressão anterior está representado naFigura 31

Embora a grande maioria dos templos Gregos fossem de formato rec-tangular, também foram construídos templos de formato circular a que cha-maram Tholos. O Santuário de Atenas Pronaia, em Delfos, contém um bom

151

Page 153: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 31: Uma perspectiva do peristilo do templo de Segesta. As colunasforam geradas pela função peristilo-dorico usando, como parâme-tros, 6 colunas na fronte e 14 no lado, com distância intercolunar de 4.8metros na fronte e 4.6 metros no lado e colunas de 9 metros de altura.

152

Page 154: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 32: O Templo de Atenas Pronaia em Delfos, construído no séculoquarto antes de Cristo. Fotografia de Michelle Kelley

exemplo de um destes edifícios. Embora pouco reste deste templo, nãoé difícil imaginar a sua forma original a partir do que ainda é visível naFigura 32.

Para simplificar a construção 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 cilindrosachatados, sobrepostos de modo a formar degraus circulares, tal como seapresenta na Figura 33. Desta forma, a altura total da base ab será divididaem passos de ∆ab e o raio da base também será reduzido em passos de ∆rb.

Para cada cilindro teremos de considerar o seu raio e a altura do es-pelho do degrau d-altura. Para passarmos ao cilindro seguinte temosainda de ter em conta o aumento do raio d-raio devido ao comprimentodo cobertor do degrau. Estes degraus serão construídos segundo um pro-cesso recursivo:

• Se o número de degraus a colocar é zero, não é preciso fazer nada.

• Caso contrário, colocamos um degrau (modelado por um cilindro)com o raio e a altura do degrau e, recursivamente, colocamos os res-tantes degraus em cima deste, i.e., numa cota igual à altura do degrau

153

Page 155: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

x

z

∆rb

rb

∆ab

rp

Figura 33: Corte da base de um Tholos. A base é composta por uma sequên-cia de cilindros sobrepostos cujo raio de base rb encolhe de ∆rb a cada de-grau e cuja altura incrementa ∆ab a cada degrau.

154

Page 156: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

agora colocado e com um raio reduzido do comprimento do cobertordo degrau agora colocado.

Este processo é implementado pela seguinte função:

(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-alturad-raio))))

Para o posicionamento das colunas, vamos também considerar um pro-cesso em que em cada passo apenas posicionamos uma coluna numa dadaposição e, recursivamente, colocamos as restantes colunas a partir da posi-ção circular seguinte.

Dada a sua estrutura circular, a construção deste género de edifícios ésimplificada pelo uso de coordenadas circulares. De facto, podemos conce-ber um processo recursivo que, a partir do raio rp do peristilo e do ânguloinicial φ, coloca uma coluna nessa posição e que, de seguida, coloca as res-tantes colunas usando o mesmo raio mas incrementando o ângulo φ de∆φ, tal como se apresenta na Figura 34. O incremento angular ∆φ obtém-se pela divisão da circunferência pelo número n de colunas a colocar, i.e.,∆φ = 2π

n . Uma vez que as colunas se dispõem em torno de um círculo,o cálculo das coordenadas de cada coluna fica facilitado pelo uso de coor-denadas polares. Tendo este algoritmo em mente, a definição da funçãofica:

(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-fialtura))))

Finalmente, definimos a função tholos que, dados os parâmetros ne-cessários às duas anteriores, as invoca em sequência:

155

Page 157: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

y

z

x

ab

rb rp

ap

rp

φ∆φ

Figura 34: Esquema da construção de um Tholos: rb é o raio da base, rp é adistância do centro das colunas ao centro da base, ap é a altura das coluna,ab é a altura da base, φ é o ângulo inicial de posicionamento das colunas e∆φ é o ângulo entre colunas.

156

Page 158: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 35: Perspectiva do Tholos de Atenas em Delfos, constituído por 20colunas de estilo Dórico, de 4 metros de altura e colocadas num círculo com7 metros de raio.

(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-colunasrp0(/ 2*pi n-colunas)ap))

A Figura 35 mostra a imagem gerada pela avaliação da seguinte expres-são:

(tholos (xyz 0 0 0) 3 7.9 0.2 0.2 20 7 4)

Exercício 7.16.1 Uma observação atenta do Tholos apresentado na Figura 35 mostra queexiste um erro: os ábacos das várias colunas são paralelos uns aos outros (e aos eixos dasabcissas e ordenadas) quando, na realidade, deveriam ter uma orientação radial. Essa dife-rença é evidente quando se compara uma vista de topo do desenho actual (à esquerda) coma mesma vista daquele que seria o desenho correcto (à direita):

157

Page 159: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Defina uma nova função coluna-dorica-rodada que, para além da altura da co-luna, recebe ainda o ângulo de rotação que a coluna deve ter. Uma vez que o fuste e ocoxim da coluna têm simetria axial, esse ângulo de rotação só influencia o ábaco, pelo quedeverá também definir uma função para desenhar um ábaco rodado.

De seguida, redefina a função colunas-tholos de modo a que cada coluna estejaorientada correctamente relativamente ao centro do Tholos.

Exercício 7.16.2 Considere a construção de uma torre composta por vários módulos emque cada módulo tem exactamente as mesmas características de um Tholos, tal como seapresenta na figura abaixo, à esquerda:

O topo da torre tem uma forma semelhante à da base de um Tholos, embora com maisdegraus.

158

Page 160: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Defina a função torre-tholos que, a partir do centro da base da torre, do númerode módulos, do número de degraus a considerar para o topo e dos restantes parâmetrosnecessários para definir um módulo idêntico a um Tholos, constrói a torre apresentada an-teriormente.

Experimente a sua função criando uma torre composta por 6 módulos, com 10 degrausno topo, 3 degraus por módulo, qualquer deles com comprimento de espelho e de cobertorde 0.2, raio da base de 7.9 e 20 colunas por módulo, com raio de peristilo de 7 e altura decoluna de 4.

Exercício 7.16.3 Com base na resposta ao exercício anterior, redefina a construção da torrede forma a que a dimensão radial dos módulos se vá reduzindo à medida que se ganhaaltura, tal como acontece na torre apresentada no centro da imagem anterior.

Exercício 7.16.4 Com base na resposta ao exercício anterior, redefina a construção da torrede forma a que o número de colunas se vá também reduzindo à medida que se ganha altura,tal como acontece na torre da direita da imagem anterior.

Exercício 7.16.5 Considere a criação de uma cidade no espaço, composta apenas por cilin-dros com dimensões progressivamente mais pequenas, unidos uns aos outros por intermé-dio de esferas, tal como se apresenta (em perspectiva) na imagem seguinte:

159

Page 161: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Defina uma função que, a partir do centro da cidade e do raio dos cilindros centraisconstrói uma cidade semelhante à representada.

7.17 A Ordem Jónica

A voluta foi um dos elementos arquitectónicos introduzidos na transição daOrdem Dórica para a Ordem Jónica. Uma voluta é um ornamento em formade espiral colocado em cada extremo de um capitel Jónico. A Figura 36mostra um exemplo de um capitel Jónico contendo duas volutas. Emboratenham sobrevivido inúmeros exemplos de volutas desde a antiguidade,nunca foi claro o processo do seu desenho.

Vitrúvio, no seu tratado de arquitectura, descreve a voluta Jónica: umacurva em forma de espiral que se inicia na base do ábaco, desenrola-senuma série de voltas e junta-se a um elemento circular denominado o olho.

Vitrúvio descreve o processo de desenho da espiral através da compo-sição de quartos de circunferência, começando pelo ponto mais exterior ediminuindo o raio a cada quarto de circunferência, até se dar a conjunçãocom o olho. Nesta descrição há ainda alguns detalhes por explicar, em par-ticular, o posicionamento dos centros dos quartos de circunferência, masVitrúvio refere que será incluida uma figura e um cálculo no final do livro.

Infelizmente, nunca se encontrou essa figura ou esse cálculo, ficandoassim por esclarecer um elemento fundamental do processo de desenho de

160

Page 162: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 36: Volutas de um capitel Jónico. Fotografia de See Wah Cheng.

volutas descrito por Vitrúvio. As dúvidas sobre esse detalhe tornaram-seainda mais evidentes quando a análise de muitas das volutas que sobrevi-veram a antiguidade revelou diferenças em relação às proporções descritaspor Vitrúvio.

Durante a Renascença, estas dúvidas levaram os investigadores a re-pensar o método de Vitrúvio e a sugerir interpretações pessoais ou novosmétodos para o desenho da voluta. De particular relevância foram os mé-todos propostos por:

• Sebastiano Serlio (1537), baseado na composição de semi-circunferências,

• Giuseppe Salviati (1552), baseado na composição de quartos-de-circun-ferência e

• Guillaume Philandrier (1544), baseado na composição de oitavos-de-circunferência.

Todos estes métodos diferem em vários detalhes mas, de forma gené-rica, todos se baseiam em empregar arcos de circunferência de aberturaconstante mas raio decrescente. Obviamente, para que haja continuidadenos arcos, os centros dos arcos vão mudando à medida que estes vão sendodesenhados. A Figura 37 esquematiza o processo para espirais feitas em-pregando quartos de circunferência.

161

Page 163: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

P

r

~v0

r · fP1

~v1

r · f · f

P2

~v2

P3

r · f · f · f

Figura 37: O desenho de uma espiral com arcos de circunferência.

162

Page 164: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Como se vê pela figura, para se desenhar a espiral temos de ir dese-nhando sucessivos quartos de circunferência. O primeiro quarto de circun-ferência será centrado no ponto P e terá raio r. Este primeiro arco vai desdeo ângulo π/2 até ao ângulo π. O segundo quarto de circunferência será cen-trado no ponto P1 e terá raio r · f , sendo f um coeficiente de “redução” daespiral. Este segundo arco vai desde o ângulo π até ao ângulo 3

2π. Um deta-lhe importante é a relação entre as coordenadas P1 e P : para que o segundoarco tenha uma extremidade coincidente com o primeiro arco, o seu centrotem de estar na extremidade do vector ~v0 de origem em P , comprimentor(1− f) e ângulo igual ao ângulo final do primeiro arco.

Este processo deverá ser seguido para todos os restantes arcos de cir-cunferência, i.e., teremos de calcular as coordenadas P2, P3, etc., bem comoos raios r · f · f , r · f · f · f , etc, necessários para traçar os sucessivos arcosde circunferência.

Dito desta forma, o processo de desenho parece ser complicado. Noentanto, é possivel reformulá-lo de modo a ficar muito mais simples. Defacto, podemos pensar no desenho da espiral completa como sendo o de-senho de um quarto de circunferência seguido do desenho de uma espiralmais pequena. Mais concretamente, podemos especificar o desenho da es-piral de centro no ponto P , raio r e ângulo inicial θ como sendo o desenhode um arco de circunferência de raio r centrado em P com ângulo inicial θe final θ + π

2 seguido de uma espiral de centro em P + ~v, raio r · f e ânguloinicial θ+ π

2 . O vector ~v terá origem em P , módulo r(1− f) e ângulo θ+ π2 .

Obviamente, sendo este um processo recursivo, é necessário definir ocaso 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 onosso raciocínio, vamos definir a função que desenha a espiral de modo areceber, como parâmetros, o ponto inicial p, o raio inicial r, o ângulo iniciala-ini, o ângulo final a-fin e o factor de redução f:

(defun espiral (p r a-ini a-fin f)(if (> a-ini a-fin)nil(progn(quarto-circunferencia p r a-ini)(espiral (+pol p (* r (- 1 f)) (+ a-ini (/ pi 2)))

(* r f)

163

Page 165: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(+ a-ini (/ pi 2))a-finf))))

Reparemos que a função espiral é recursiva pois está definida emtermos de si própria. Obviamente, o caso recursivo é mais simples que ocaso original pois a diferença entre o ângulo inicial e o final é mais pequena,aproximando-se progressivamente do caso de paragem em que o ânguloinicial ultrapassa o final.

Para desenhar o quarto de circunferência vamos empregar a operaçãoarc do Auto Lisp que recebe o centro do circunferência, o ponto inicial doarco e o ângulo em graus. Para melhor percebermos o processo de dese-nho da espiral vamos também traçar duas linhas com origem no centro adelimitar cada quarto de circunferência. Mais tarde, quando tivermos ter-minado o desenvolvimento destas funções, removeremos essas linhas.

Desta forma, o quarto de circunferência apenas precisa de saber o pontop correspondente ao centro da circunferência, o raio r da mesma e o ânguloinicial 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 traçada pela expressão anterior está representada na Figura 38.A função espiral permite-nos definir um sem-número de espirais,

mas tem uma restrição: cada arco de círculo corresponde a um ângulo deπ2 . Logicamente, a função tornar-se-á mais útil se também este incrementode ângulo for um parâmetro.

As modificações a fazer são relativamente triviais, bastando acrescen-tar um parâmetro a-inc representando o incremento de ângulo de cadaarco e substituir as ocorrências de (/ pi 2) por este parâmetro. Natural-mente, em vez de desenharmos um quarto de circunferência, temos agorade desenhar um arco de circunferência.

A nova definição é, então:

(defun espiral (p r a-ini a-inc a-fin f)(if (> a-ini a-fin)nil

164

Page 166: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

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-inca-finf))))

A função que desenha o arco é uma variante da que desenha o quartode circunferência. Apenas é preciso ter em conta que o comando arc pre-tende o ângulo em graus e não em radianos, o que nos obriga a usar umaconversão:

(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, temosde avaliar a expressão:

165

Page 167: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 39: Várias espirais com razões de redução de 0.9, 0.7 e 0.5, respecti-vamente.

(espiral (xy 0 0) 10 (/ pi 2) (/ pi 2) (* pi 6) 0.8)

É claro que agora podemos facilmente construir outras espirais. As se-guintes expressões 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)

Outra possibilidade de variação está no ângulo de incremento. As se-guintes expressões experimentam aproximações aos processos de Sebasti-ano Serlio (semi-circunferências), Giuseppe Salviati (quartos-de-circunferência)e Guillaume Philandrier (oitavos-de-circunferência):48

(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 estão representados na Figura 40.

48Note-se que se trata, tão somente, de aproximações. Os processos originais eram bas-tante mais complexos.

166

Page 168: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 40: Várias espirais com razão de redução de 0.8 e incremento deângulo de π, π2 e π

4 , respectivamente.

Exercício 7.17.1 Um óvulo é uma figura geomética que corresponde ao contorno dos ovosdas aves. Dada a variedade de formas de ovos na Natureza, é natural considerar que tam-bém existe uma grande variedade de óvulos geométrivos. A figura seguinte apresenta al-guns exemplos em que se variam sistematicamente alguns dos parâmetros que caracteri-zam o óvulo:

Um óvulo é composto por quatro arcos de circunferência concordantes, tal como seapresenta na imagem seguinte:

167

Page 169: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

P

r0

r2 r2

α α

r1

Os arcos de círculos necessários para a construção do ovo são caracterizados pelos raiosr0, r1 e r2. Note que o arco de circunferência de raio r0 cobre um ângulo de π e o arco decircunferência de raio r2 cobre um ângulo de α.

Defina uma função ovo que desenha um ovo. A função deverá receber, apenas, ascoordenadas do ponto P , os raios r0 e r1 e, finalmente, a altura h do ovo.

7.18 Recursão na Natureza

A recursão está presente em inúmeros fenómenos naturais. As montanhas,por exemplo, apresentam irregularidades que, quando observadas numaescala apropriada, são em tudo idênticas a . . . montanhas. Um rio pos-sui afluentes e cada afluente é idêntico a . . . um rio. Uma vaso sanguíneopossui ramificações e cada ramificação é idêntica a . . . um vaso sanguíneo.Todas estas entidades naturais constituem exemplos de estruturas recursi-vas.

Uma árvore é outro bom exemplo de uma estrutura recursiva pois osramos de uma árvore são como pequenas árvores que emanam do tronco.Como se pode ver da Figura 41, de cada ramo de uma árvore emanamoutras pequenas árvores, num processo que se repete até se atingir uma di-mensão suficientemente pequena em que aparecem outras estruturas comofolhas, flores, frutos, pinhas, etc.

Se, de facto, uma árvore possui uma estrutura recursiva então deveráser possível “construir” árvores através de funções recursivas. Para tes-

168

Page 170: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 41: A estrutura recursiva das árvores. Fotografia de Michael Bez-zina.

169

Page 171: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(x0, y0)

αα

c

f · cf · c

Figura 42: Parâmetros de desenho de uma árvore.

tarmos esta teoria, vamos começar por considerar uma versão muito sim-plista de uma árvore, em que temos um tronco que, a partir de uma certaaltura, se divide em dois. Cada um destes subtroncos cresce fazendo umcerto ângulo com o tronco de onde emanou e com um comprimento quedeverá ser uma fracção do comprimento desse tronco, tal como se apre-senta na Figura 42. O caso de paragem ocorre quando o comprimento dotronco se tornou tão pequeno que, em vez de se continuar a divisão, apa-rece simplesmente uma outra estrutura. Para simplificar, vamos designar aextremidade de um ramo por folha e iremos representá-la com um pequenocírculo.

Para darmos dimensões à árvore, vamos considerar que a função arvorerecebe, como argumento, as coordenadas da base da árvore, o comprimentodo tronco e o ângulo actual do tronco. Para a fase recursiva, teremos comoparâmetros o ângulo de abertura alpha que o novo tronco deverá fazercom o actual e o factor de redução f do comprimento do tronco. O pri-meiro passo é a computação do topo do tronco usando a função +pol. Emseguida, desenhamos o tronco desde a base até ao topo. Finalmente, testa-mos se o tronco desenhado é suficientemente pequeno. Se for, terminamoscom o desenho de um círculo centrado no topo. Caso contrário fazemosuma dupla recursão para desenhar uma sub-árvore para a direita e outrapara a esquerda. A definição da função fica:

(defun arvore (base comprimento angulo alfa f / topo)(setq topo (+pol base comprimento angulo))(ramo base topo)(if (< comprimento 2)(folha topo)(progn

170

Page 172: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 43: Uma “árvore” de comprimento 20, ângulo inicial π2 , abertura π8

e factor de redução 0.7.

(arvore topo(* comprimento f)(+ angulo alfa)alfa f)

(arvore topo(* comprimento f)(- angulo alfa)alfa f))))

(defun ramo (base topo)(command "_.line" base topo ""))

(defun folha (topo)(command "_.circle" topo 0.2))

Um primeiro exemplo de árvore gerado com a expressão

(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 redução. A sequência de expressões que as geroufoi a seguinte:

(arvore (xy 0 0) 20 (/ pi 2) (/ pi 8) 0.6)

(arvore (xy 100 0) 20 (/ pi 2) (/ pi 8) 0.8)

171

Page 173: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 44: Várias “árvores” geradas com diferentes ângulos de abertura efactores de redução do comprimento dos ramos.

(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 são “excessivamente” simétricas:no mundo natural é literalmente impossível encontrar simetrias perfeitas.Por este motivo, convém tornar o modelo um pouco mais sofisticado atra-vés da introdução de parâmetros diferentes para o crescimento dos troncosà direita e à esquerda. Para isso, em vez de termos um só ângulo de aber-tura e um só factor de redução de comprimento, vamos empregar dois, talcomo se apresenta na Figura 45.

A adaptação da função arvore para lidar com os parâmetros adicio-nais é trivial:

(defun arvore (base comprimento anguloalfa-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)

172

Page 174: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

(x0, y0)

αdαe

c

fd · cfe · c

Figura 45: Parâmetros de desenho de uma árvore com crescimento assimé-trico.

(+ 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 ângu-los de abertura e factores de redução dos ramos esquerdo e direito, geradaspelas seguintes expressões:

(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 função arvore são apenas um modelo muitogrosseiro da realidade. Embora existam sinais evidentes de que vários fe-nómenos naturais se podem modelar através de funções recursivas, a na-tureza não é tão determinista quanto as nossas funções e, para que a mo-delação se aproxime mais da realidade, é fundamental incorporar tambémalguma aleatoriedade. Esse será o tema da próxima seccção.

173

Page 175: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Figura 46: Várias árvores geradas com diferentes ângulos de abertura efactores de redução do comprimento para os ramos esquerdo e direito.

174

Page 176: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Função Argumentos Resultado+ Vários números A adição de todos os argumentos. Sem ar-

gumentos, zero.- Vários números Com apenas um argumento, o seu simé-

trico. Com mais de um argumento, a sub-tracção ao primeiro de todos os restantes.Sem argumentos, zero.

* Vários números A multiplicação de todos os argumentos.Sem argumentos, zero.

/ Vários números A divisão do primeiro argumento por to-dos os restantes. Sem argumentos, zero.

1+ Um número A soma do argumento com um.1- Um número A substracção do argumento com um.abs Um número O valor absoluto do argumento.sin Um número O seno do argumento (em radianos).cos Um número O cosseno do argumento (em radianos).atan Um ou dois nú-

merosCom um argumento, o arco tangente do ar-gumento (em radianos). Com dois argu-mentos, o arco tangente da divisão do pri-meiro pelo segundo (em radianos). O sinaldos argumentos é usado para determinar oquadrante.

sqrt Um número nãonegativo

A raiz quadrada do argumento.

exp Um número A exponencial de base e.expt Dois números O primeiro argumento elevado ao segundo

argumento.log Um número po-

sitivoO logaritmo natural do argumento.

max Vários números O maior dos argumentos.min Vários números O menor dos argumentos.rem Dois ou mais

númerosCom dois argumentos, o resto da divisãodo primeiro pelo segundo. Com mais ar-gumentos, o resto da divisão do resultadoanterior pelo argumento seguinte.

fix Um número O argumento sem a parte fraccionária.float Um número O argumento convertido em número real.gcd Dois números O maior divisor comum dos dois argumen-

tos.

Tabela 2: Funções matemáticas pré-definidas do Auto Lisp.175

Page 177: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Auto Lisp Matemática(+ x0 x1 ... xn) x0 + x1 + . . . + xn(+ x) x

(+) 0(- x0 x1 ... xn) x0 − x1 − . . . − xn(- x) −x(-) 0(* x0 x1 ... xn) x0 × x1 × . . . × xn(* x) x

(*) 0(/ x0 x1 ... xn) x0/x1/ . . . /xn(/ x) x

(/) 0(1+ x) x+ 1(1- x) x− 1(abs x) |x|(sin x) sinx(cos x) cosx(atan x) atanx(atan x y) atan x

y

(sqrt x)√x

(exp x) ex

(expt x y) xy

(log x) log x(fix x) bxc

Tabela 3: Funções matemáticas pré-definidas do Auto Lisp.

176

Page 178: António Menezes Leitão Fevereiro 2007 - Autenticação · 2 Sintaxe, Semântica e Pragmática 13 ... dos últimos milénios com a construção de uma linguagem onde o rigor seja

Função Argumentos Resultadostrcat Várias strings A concatenação de todos os argumentos.

Sem argumentos, a string vazia .strlen Várias strings O número de caracteres da concatenação

das strings. Sem argumentos, devolvezero.

substr Uma string,um inteiro (oíndice) e, op-cionalmente,outro inteiro(o número decaracteres)

A parte da string que começa no índicedado e que tem o número de caracteresdado ou todos os restantes caracteres nocaso de esse número não ter sido dado.

strcase Uma string eum boleanoopcional

Com um argumento ou segundo argu-mento nil, a conversão para maiúsculasdo argumento, caso contrário, conversãopara minúsculas.

atof Uma string O número real cuja representação textualé o argumento.

atoi Uma string O número, sem a parte fraccionária, cujarepresentação textual é o argumento.

itoa Um número A representação textual do argumento.rtos Um, dois ou três

númerosA representação textual do argumento,de acordo com o modo especificado nosegundo argumento e com a precisão es-pecificada no terceiro argumento.

Tabela 4: Operações pré-definidas envolvendo strings.

177