António Menezes Leitão Fevereiro 2007 · inada de homotetia. Embora seja possível ter uma...

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

Transcript of António Menezes Leitão Fevereiro 2007 · inada de homotetia. Embora seja possível ter uma...

Introdução à Programação com AutoLisp

António Menezes Leitão

Fevereiro 2007

Conteúdo

1 Transformações 21.1 Translação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.2 Rotação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.3 Reflexão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.4 Escala . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.5 A Ópera de Sydney . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2 Funções de Ordem Superior 142.1 Fachadas Curvilíneas . . . . . . . . . . . . . . . . . . . . . . . . . 142.2 Funções de Ordem Superior . . . . . . . . . . . . . . . . . . . . . 202.3 Funções Anónimas . . . . . . . . . . . . . . . . . . . . . . . . . . 222.4 Funções Anónimas e Variáveis Locais . . . . . . . . . . . . . . . 272.5 Âmbito e Duração . . . . . . . . . . . . . . . . . . . . . . . . . . . 272.6 Funções de Ordem Superior e Variáveis Livres . . . . . . . . . . 312.7 Representação Paramétrica . . . . . . . . . . . . . . . . . . . . . 34

2.7.1 Computação de Funções Paramétricas . . . . . . . . . . . 352.7.2 Erros de Arredondamento . . . . . . . . . . . . . . . . . . 372.7.3 Precisão . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

2.8 Espiral de Fermat . . . . . . . . . . . . . . . . . . . . . . . . . . . 422.9 Cissóide de Diocles . . . . . . . . . . . . . . . . . . . . . . . . . . 442.10 Lemniscata de Bernoulli . . . . . . . . . . . . . . . . . . . . . . . 462.11 Curva de Lamé . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482.12 Catenária . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542.13 Pontos Fixos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

2.13.1 O Arco de St. Louis . . . . . . . . . . . . . . . . . . . . . . 622.14 Funções de Ordem Superior sobre Listas . . . . . . . . . . . . . . 67

2.14.1 Mapeamento . . . . . . . . . . . . . . . . . . . . . . . . . 672.14.2 Filtragem . . . . . . . . . . . . . . . . . . . . . . . . . . . 672.14.3 Redução . . . . . . . . . . . . . . . . . . . . . . . . . . . . 682.14.4 Bestialidades . . . . . . . . . . . . . . . . . . . . . . . . . 682.14.5 Funções de Ordem Superior com Múltiplas Listas . . . . 71

1

1 Transformações

Até agora, todos os objectos que construímos possuem um carácter definitivo:os parâmetros usados para os construir determinam univocamente a formadesses objectos e tudo o que podemos fazer é invocar as funções que con-stroem esses objectos com diferentes parâmetros para construirmos objectosdiferentes.

Embora essa forma de construção de objectos seja suficientemente poderosapara nos permitir uma fácil modelação, existem alternativas potencialmentemais práticas que se baseiam na modificação de objectos previamente criados.Essa modificação é realizada através de operações de translação, rotação, reflexãoe escala.

É importante salientarmos que estas operações não criam novos objectos,apenas afectam aqueles a que se aplicam. Por exemplo, após a aplicação deuma translacção a um objecto, este objecto muda simplesmente de posição.

Por vezes, contudo, poderemos pretender aplicar transformações a objec-tos que produzam novos objectos como resultado. Por exemplo, poderemosquerer fazer a reflexão de um objecto, mas deixando o objecto original no seulugar. Uma forma de o conseguirmos será aplicar a operação de reflexão, nãoao objecto original, mas sim a uma sua cópia. A possibilidade de criarmoscópias dos objectos pode então ser usada para distinguirmos o caso em quequeremos que uma operação modique um objecto do caso em que queremosque uma operação crie um novo objecto. Por este motivo, vamos começarpor implementar uma operação de cópia. O AutoCad disponibiliza a op-eração copy que, para além dos objectos a copiar, recebe um deslocamentodefinido por dois pontos. No nosso caso, é preferível deixar este desloca-mento como nulo para que seja a aplicação de outras operações (nomeada-mente, translacções) a efectuar esse deslocamento. No final da cópia, devolve-mos a entidade recém-criada. Assim, temos:

(defun copia (regiao)(inicio-operacao)(command "_.copy" regiao "" origem origem)(fim-operacao))

1.1 Translação

A operação de translação move um objecto através da adição de um vector atodos os seus pontos, fazendo com que todos os pontos se movam uma de-terminada distância numa determinada direcção. Os componentes do vectorindicam qual o deslocamento relativamente a cada um dos eixos coordenados.

Para realizar esta operação o AutoCad disponibiliza a operação move que,para além de várias outras possibilidades, permite, através da especificaçãoda opção displacement, que se use um vector deslocamento para realizara operação de translação. Para simplificar a utilização desta operação, vamoscomeçar por definir uma função que a invoca com os parâmetros adequados:

(defun translacao (vector regiao)

2

(command "_.move" regiao "" "_displacement" vector)regiao)

Notemos que a função devolve a entidade que sofreu a translação parapermitir o seu fácil encadeamento com outras operações.

1.2 Rotação

Na rotação, todos os pontos de um objecto giram num movimento circular emtorno de um ponto (a duas dimensões) ou eixo (a três dimensões). No casogeral de uma rotação a três dimensões é usual decompor-se esta em três ro-tações sucessivas em torno dos eixos coordenados. Estas rotações em tornodos eixos X, Y e Z designam-se rotações principais, por analogia com o conceitode eixos principais que se aplica a X, Y e Z.

Contrariamente ao que acontecia com a operação anterior, esta transfor-mação já está implementada no Auto Lisp através da função rotate3d, definidana biblioteca de funções geom3d. Antes de a podermos usar, é necessário “car-regarmos” esta biblioteca para o Auto Lisp usando, para isso, a seguinte ex-pressão:

(arxload "geom3d")

Uma vez carregada a biblioteca, a função rotate3d pode ser usada com asmesmas opções que o comando correspondente. Para os nossos propósitos, ocomando rotate3d é excessivamente flexível e, para facilitar a programação,vamos criar uma particularização do comando para realizar três rotações emtorno dos eixos coordenados. Para isso, vamos explorar as opções xaxis,yaxis e zaxis, que realizam a rotação em torno do eixo correspondente eque apenas necessitam do ângulo pretendido, especificado em graus. Uma vezque, do ponto de vista da programação, a utilização de radianos é preferível àutilização de graus, vamos realizar internamente a conversão para o formatoexigido pela função rotate3d:1

(defun rotacao (rx ry rz regiao)(if (zerop rx)

nil(rotate3d regiao "_xaxis" origem

(graus<-radianos rx)))(if (zerop ry)

nil(rotate3d regiao "_yaxis" origem

(graus<-radianos ry)))

1As versões actuais do AutoCad possuem uma limitação importante que impedem a correctautilização, via Auto Lisp, dos comandos que estão definidos por bibliotecas. Assim, ao invésda expressão que invoca o comando c:rotate3d:(command "_.rotate3d" objecto "_xaxis" ponto graus)

devemos usar directamente a função rotate3d:(rotate3d objecto "_xaxis" ponto graus)

Se não o fizermos, ao fim de algumas invocações do comando c:rotate3d, o AutoCad geraum erro.

3

(if (zerop rz)nil(rotate3d regiao "_zaxis" origem

(graus<-radianos rz)))regiao)

É importante recordarmos que, numa rotação sobre os três eixos coordena-dos, a rotação em torno do eixo X é realizada antes da rotação em torno doeixo Y que é realizada antes da rotação em torno do eixo Z.

1.3 Reflexão

Para além da translação e rotação, o AutoCad implementa a operação de re-flexão. Na realidade, esta operação é mais fundamental que a rotação ou atranslacção pois estas podem ser implementadas em termos daquela.

O AutoCad implementa a operação de reflexão através do comando mirrorpara o caso bidimensional e mirror3d para o caso tridimensional. Neste úl-timo caso, tal como já acontecia com a rotação, também este comando se en-contra implementado por uma função da biblioteca geom3d, pelo que a dev-eremos usar no lugar da invocação do comando.

A reflexão tridimensional em AutoCad permite múltiplas opções para aoperação pretendida sendo a mais simples a que se baseia na indicação doplano para a reflexão através de um ponto contido nesse plano e do vector nor-mal ao plano. Uma outra opção importante é a que permite escolher preservarou não o objecto antes da reflexão. Para os nossos propósitos, é preferível quenão se preserve esse objecto, de modo a que a reflexão tenha um comporta-mento idêntico ao da translacção e da rotação. Tendo estas opções em conta,podemos definir uma função apropriada:

(defun reflexao (p normal regiao)(mirror3d regiao "_zaxis" p (+c p normal) "_yes")regiao)

Se quisermos criar a reflecção de um objecto e uni-la com o seu original,podemos definir a função uniao-reflexao:

(defun uniao-reflexao (p normal regiao)(uniao regiao

(reflexao p normal (copia regiao))))

1.4 Escala

A escala consiste de uma transformação que aumenta ou diminui a dimensãode uma entidade sem lhe modificar a forma. Esta operação é também denom-inada de homotetia. Embora seja possível ter uma operação de escala que mod-ifica independentemente cada uma das dimensões, a variante mais usual é aescala uniforme que modifica simultaneamente as três dimensões, afectando-as de um mesmo factor. Se o factor é maior que um, o tamanho aumenta. Se ofactor é menor que um, o tamanho diminui.

4

Figura 1: A Ópera de Sydney.

No caso do AutoCad, apenas é disponibilizada uma operação de escalauniforme: scale. Tal como foi feito para a operação de translação, torna-semais conveniente a utilização de uma função que invoca este comando:

(defun escala (factor regiao)(command "_.scale" regiao "" origem factor)regiao)

É fácil vermos que a escala, para além de alterar a dimensão do objecto,altera também a sua posição. Se esse efeito não for pretendido, a solução óbviaé aplicar previamente uma translação para centrar o objecto na origem, aplicarde seguida a operação de escala e, finalmente, aplicar a translação inversa para“devolver” o objecto à sua posição original.

Na secção seguinte iremos ver um exemplo em que estas operações irão serutilizadas para a modelação de um dos edifícios mais famosos do mundo.

1.5 A Ópera de Sydney

A Ópera de Sydney resultou de um concurso internacional lançado em 1957para a construção de um edifício destinado à realização de espectáculos. Ovencedor foi o projecto de Jørn Utzon, um arquitecto Dinamarquês pouco con-hecido até então. O seu projecto, embora não cumprisse integralmente os req-uisitos do concurso, foi seleccionado pelo famoso arquitecto Eero Saarinen, en-tão membro do júri, que a considerou desde logo como uma obra marcante. Aproposta consistia de um conjunto de estruturas em forma de concha capazesde albergar várias salas de espectáculos. O resultado final desta proposta estárepresentado na Figura 1.

Claramente inovador, o desenho de Utzon estava demasiado avançadopara as tecnologias de projecto e construção da época e foi por muitos con-

5

Figura 2: Placa comemorativa que explica a idéia de Utzon para a modelaçãodas conchas. Fotografia de Matt Prebble, Reino Unido, Dezembro 2006.

siderado como impossível. Nos três anos subsequentes à aprovação do pro-jecto, Utzon, juntamente com a equipa de engenharia estrutural da empresaOve Arup, tentou encontrar uma formulação matemática para as suas conchasdesenhadas à mão, tendo experimentado uma grande variedade de diferentesabordagens, incluindo formas parabólicas, circulares e elípticas, mas todas assoluções encontradas tinham, para além de enormes dificuldades técnicas deconstrução, um custo elevadíssimo que era totalmente incompatível com oorçamento aprovado.

No verão de 1961, Utzon estava perto do limiar do desespero e decidiu des-mantelar o modelo de perspex das conchas. Contudo, ao arrumar as conchas,descobriu que elas se ajustavam quase perfeitamente umas dentro das outras,o que apenas seria possível se as diferentes conchas tivessem a mesma cur-vatura em todos os pontos. Ora a superfície que possui a mesma curvatura emtodos os pontos é, obviamente, a esfera, o que levou Utzon a pensar que talvezfosse possível modelar as suas conchas como triângulos “cortados” na superfí-cie de uma esfera. Embora esta modelação não fosse exactamente idêntica aosdesenhos originais de Utzon, ela tinha a vantagem de ser calculável em com-putadores e, ainda mais importante, de permitir a sua construção económica.A colaboração da equipa de Ove Arup foi crucial para que a idéia de Utzonpudesse passar da teoria à prática mas o rasgo de génio que permitiu resolveros problemas de construção é, tal como o desenho original, de Utzon. Estaidéia de Utzon está explicada num modelo de bronze colocado junto ao edifí-cio da Ópera, tal como se pode ver na Figura 2.

Infelizmente, os atrasos na construção bem como os custos elevados que

6

Figura 3: Duas das meia-conchas que constituem a Ópera de Sydney sobre-postas às esferas de onde foram obtidas por uma sucessão de cortes.

se estavam a acumular levaram o governo a questionar a decisão política deconstruir a Ópera e forçaram Utzon a demitir-se quando ainda faltava a con-strução dos interiores. Utzon ficou destroçado e abandonou a Austrália em1966 para nunca mais voltar. Contra a vontade da maioria dos arquitectos,a sua obra-prima foi completada por Peter Hall e inaugurada em 1973 semque se fizesse uma única referência a Utzon. Infelizmente, o trabalho de PeterHall não esteve ao mesmo nível do de Utzon e o contraste entre os magnífi-cos exteriores e os banais interiores levou a que a obra fosse considerada uma“semi-obra-prima.”2

Nesta secção, vamos modelar as conchas da Ópera de Sydney seguindo ex-actamente a mesma solução proposta por Utzon. Todas as conchas do edifícioserão modeladas por triângulos esféricos obtidos através de três cortes numaesfera. A Figura 3 mostra duas esferas de igual raio onde cortámos um triân-gulo em cada uma, de forma a obter duas das meias-conchas que constituema Ópera de Sydney.

Para definir os cortes podemos considerar que edifício irá ficar alinhadonuma paralela ao eixo dos Y pelo que o eixo de simetria corresponde a umplano de corte cuja normal é o eixo dosX , tal como se visualiza na Figura 4. Osdois restantes planos de corte terão normais determinadas de modo a aprox-imar, tão rigorosamente quanto nos é possível, a volumetria imaginada porUtzon. Como é também visível na Figura 4, cada concha é extraída de umaesfera com raio fixo mas que é centrada em diferentes pontos. Assim, para

2Apesar do drama pessoal de Utzon, esta história ainda pode vir a ter um final feliz: trintaanos mais tarde, o governo Australiano está a remodelar a Ópera de Sydney para a transformarna verdadeira obra-prima que ela merece ser e conseguiu que Utzon, que nunca chegou a ver asua obra acabada, aceitasse dirigir os trabalhos que visam devolver-lhe o aspecto original.

7

Figura 4: Vista de topo de duas das meia-conchas que constituem a Ópera deSydney sobrepostas às esferas de onde foram obtidas por uma sucessão decortes.

modelar estas meias-conchas vamos definir uma função que, a partir do cen-tro p da esfera de raio r e das normais n1 e n2 dos planos de corte, produz umacasca esférica de espessura e com a forma pretendida.

(defun meia-concha (p r e n1 n2)(translacaop(corte(*c -eixo-x (cx p)) -eixo-x(corteorigem n1(corteorigem n2(subtraccao(esfera origem r)(esfera origem (- r e))))))))

A título de exemplo, a Figura 5 mostra uma meia concha produzida pelaavaliação da expressão:

(meia-concha (xyz -45 0 0) 75 2 (esf 1 2.0 4.6) (esf 1 1.9 2.6))

Para fazer uma concha completa temos apenas de aplicar uma reflexão àmeia-concha, segundo o plano de corte vertical:

(defun concha (p r e n1 n2)(uniao-reflexaoorigem-eixo-x(meia-concha p r e n1 n2)))

8

Figura 5: Uma meia concha da Ópera de Sydney.

A Figura 6 mostra a concha produzida pela avaliação da expressão:

(concha (xyz -45 0 0) 75 2 (esf 1 2.0 4.6) (esf 1 1.9 2.6))

Para definir o conjunto de conchas de um edifício vamos usar valores queaproximem as conchas produzidas do desenho original de Utzon:

(defun conchas-sydney ()(unioes(list(concha (xyz -45.01 +00.00 +00.00) 75 2

(esf 1 1.9701 4.5693) (esf 1 1.9125 2.5569))(concha (xyz -38.92 -13.41 -18.85) 75 2

(esf 1 1.9314 4.5902) (esf 1 1.7495 1.9984))(concha (xyz -38.69 -23.04 -29.89) 75 2

(esf 1 1.9324 4.3982) (esf 1 1.5177 1.9373))(concha (xyz -58.16 +81.63 -14.32) 75 2

(esf 1 1.6921 3.9828) (esf 1 1.4156 1.9618))(concha (xyz -32.00 +73.00 -05.00) 75 2

(esf 1 +00.91 4.1888) (esf 1 0.8727 1.3439))(concha (xyz -33.00 +44.00 -20.00) 75 2

(esf 1 +01.27 4.1015) (esf 1 1.1554 1.2217)))))

A invocação desta função produz a fileira de conchas que apresentamos naFigura 7.

Para facilitar o posicionamento do edifício, vamos ainda incluir uma ro-tação em torno do eixo Z, uma escala e uma translação finais aplicadas a cadaconjunto de conchas. Uma vez que o edifício possui dois conjuntos de conchas,vamos denominar esta função de meia-opera-sydney:

(defun meia-opera-sydney (rot-z esc trans-x)(translacao

9

Figura 6: Uma concha da Ópera de Sydney.

Figura 7: Uma fileira de conchas da Ópera de Sydney.

10

Figura 8: A modelação completa das conchas da Ópera de Sydney.

(xyz trans-x 0 0)(escalaesc(rotacao0 0 rot-z(conchas-sydney)))))

Finalmente, podemos modelar a ópera completa fazendo um edifício for-mado por um conjunto de conchas à escala 1.0 e um segundo edifício comouma versão reduzida, rodada e deslocada do primeiro. A escala usada porUtzon era de 80% e os ângulos de rotação e as translações que vamos usar sãoos que permitem que haja elevada semelhança com o edifício real tal como elehoje se encontra:

(defun opera-sydney ()(meia-opera-sydney +0.1964 1.0 +43)(meia-opera-sydney -0.1964 0.8 -15))

O resultado final da modelação das conchas encontra-se na Figura 8.

Exercício 1.5.1 Defina uma função que cria um elo de uma corrente, tal como se visualiza àesquerda da seguinte imagem.

11

Para simplificar a modelação, considere o elo como decomponível em quartos de elo, talcomo se visualiza à direita da imagem anterior. Deste modo, bastará definir uma função quecria um quarto de um elo (à custa de um quarto de um toro e de meio cilindro) e aplicar-lheuma dupla reflexão nos eixos X e Y para compor o elo completo.

A função deverá receber, como parâmetros, o raio do elo re, o raio do “arame” ri e o com-primento l entre semi-círculos, tal como se apresenta no seguinte esquema.

x

y

l

re

ri

Exercício 1.5.2 Defina uma função capaz de criar correntes como as que se apresentam emseguida:

12

Note que, à medida que se vai construindo a corrente, os elos vão sofrendo sucessivasrotações em torno do eixo x.

Exercício 1.5.3 As funções translacao, rotacao, reflexao e escala não sabem lidar comregiões “especiais” como sejam a região vazia e a região universal. Redefina-as para que passema ser capazes de lidar com estas regiões.

13

2 Funções de Ordem Superior

Temos demonstrado como a linguagem Auto Lisp nos permite, através dadefinição de funções apropriadas, gerarmos as formas arquitecturais que temosem mente. Uma das vantagens da definição dessas funções é que muitasdessas formas arquitecturais ficam parameterizadas, permitindo-nos facilmenteexperimentar variações até atingirmos os valores numéricos dos parâmetrosque nos satisfazem.

Apesar da “infinita” variabilidade que os parâmetros nos permitem, aindaassim existirão sempre limites naquilo que conseguimos fazer apenas com parâmet-ros numéricos e, para termos um grau superlativo de variabilidade, teremosde fazer variar as próprias funções.

Nesta secção vamos discutir funções de ordem superior. Uma função deordem superior é uma função que recebe funções como argumentos. Àparteesta particularidade, uma função de ordem superior não tem nada de diferentede outra função qualquer.

2.1 Fachadas Curvilíneas

Para motivar a discussão vamos considerar um problema simples: pretende-mos idealizar um edifício em que três dos seus lados são planos e o quarto—afachada—é uma superfície vertical curvilínea. Para começar, podemos consid-erar que essa superfície curvilínea é de forma sinusoidal.

Tal como vimos na secção ??, uma sinusóide é determinada por um con-junto de parâmetros, como seja a amplitude a, o número de ciclos por unidadede comprimento ω e a fase φ da curva em relação ao eixo dos y. Com estesparâmetros, a equação da curva sinusóide fica com a forma:

y(x) = a sin(ωx+ φ)

Para calcularmos os pontos de uma sinusóide podemos usar a função pontos-sinusoideque computa uma lista de coordenadas (x, y) correspondentes à evolução dasinusóide entre os limites de um intervalo [x0, x1], com um incremento ∆x:

(defun pontos-sinusoide (p a omega fi x0 x1 dx)(if (> x0 x1)

()(cons (+xy p x0 (sinusoide a omega fi x0))

(pontos-sinusoide p a omega fi (+ x0 dx) x1 dx))))

A função anterior gera uma lista com pontos da fachada. Para modelarmoso resto do edifício precisamos de unir esses pontos de modo a formar umacurva e precisamos de juntar a essa curva os três lados rectilineos de modo aformar uma região correspondente à planta do edifício. Para isso, vamos uniros pontos com uma spline e vamos formar uma região entre ela e com as rectasque delimitam os outros três lados do edifício. Admitindo que o edifíco temum comprimento lx e uma largura ly, temos:

(defun edificio-planta (p pontos lx ly)(regiao

14

Figura 9: Urbanização de edifícios cuja fachada corresponde a paredes sinu-soidais com parâmetros diferentes.

(list (spline-pontos pontos)(pline-pontos(list (car pontos)

(+xy p 0 ly)(+xy p lx ly)(last pontos))))))

Esta região é de seguida extrudida até à altura lz pretendida para o edifício.

(defun edificio-sinusoide (p a omega fi lx dx ly lz)(extrusao(edificio-planta

p (pontos-sinusoide p a omega fi 0 lx dx) lx ly)lz))

Para visualizarmos as capacidades da função anterior podemos construirvários edifícios usando valores diferentes dos parâmetros da sinusóide. Nasseguintes expressões considerámos duas filas de edifícios, todos com 15 metrosde comprimento, 10 metros de largura e 20 ou 30 metros de altura consoante afila. A Figura 9 mostra esses edifícios para diferentes valores dos parâmetrosa, omega e fi:

(edificio-sinusoide (xy 0 0) 0.75 0.5 0 15 0.4 10 20)(edificio-sinusoide (xy 25 0) 0.55 1.0 0 15 0.2 10 20)(edificio-sinusoide (xy 50 0) 0.25 2.0 0 15 0.1 10 20)(edificio-sinusoide (xy 0 20) 0.95 1.5 1 15 0.4 10 30)(edificio-sinusoide (xy 25 20) 0.85 0.2 0 15 0.2 10 30)(edificio-sinusoide (xy 50 20) 0.35 1.0 1 15 0.1 10 30)

Infelizmente, embora a função edificio-sinusoide seja muito útil paramodelar uma infinidade de diferentes edifícios de fachada sinusoidal, ela é to-talmente inútil para modelar edifícios cuja fachada segue uma parábola, ou

15

um logarítmo, ou uma exponencial ou, na verdade, qualquer outra curva quenão seja reduzível a uma sinusóide. De facto, embora o ajuste dos parâmetrosnos permite a infinita variabilidade do edifício modelado, ainda assim, ele serásempre um caso particular de uma fachada sinusoidal.

É claro que nada nos impede de definir outras funções para a modelaçãode fachadas diferentes. Imaginemos, por exemplo, que pretendemos umafachada com a curvatura de uma parábola. A parábola com vértice em (xv, yv)e foco em (xv, yv + d), sendo d a distância do vértice ao foco, define-se pelaseguinte equação:

(x− xv)2 = 4d(y − yv)

ou seja

y =(x− xv)2

4d+ yv

Em Auto Lisp, esta função define-se como:

(defun parabola (xv yv d x)(+ (/ (quadrado (- x xv))

(* 4 d))yv))

Para gerarmos os pontos da parábola temos, como de costume, de iterar aolongo de um intervalo [x0, x1] com um incremento ∆x:

(defun pontos-parabola (p xv yv d x0 x1 dx)(if (> x0 x1)

()(cons (+xy p x0 (parabola xv yv d x0))

(pontos-parabola p xv yv d (+ x0 dx) x1 dx))))

Finalmente, podemos definir a função que modela o edifício seguinte pre-cisamente a mesma abordagem que seguimos para a função edificio-sinusoide:

(defun edificio-parabola (p xv yv d lx dx ly lz)(extrusao

(edificio-plantap (pontos-parabola p xv yv d 0 lx dx) lx ly)

lz))

As seguintes expressões testam esta função com valores diferentes dos váriosparâmetros:

(edificio-parabola (xy 0 0) 10 0 5 15 0.5 10 20)(edificio-parabola (xy 25 0) 5 0 3 15 0.2 10 20)(edificio-parabola (xy 50 0) 7 1 -2 15 0.1 10 20)(edificio-parabola (xy 0 20) 8 0 2 15 0.4 10 30)(edificio-parabola (xy 25 20) 6 -2 3 15 0.2 10 30)(edificio-parabola (xy 50 20) 5 0 6 15 0.1 10 30)

gerando a “urbanização” representada na Figura 10.Mais uma vez, a parameterização da função edificio-parabola permite-

nos gerar uma infinidade de edifícios com fachada com a curvatura de uma

16

Figura 10: Urbanização de edifícios cuja fachada corresponde a paredesparaboloidais com parâmetros diferentes.

parábola, mas serão sempre edifícios diferentes daqueles que podemos gerarcom a função edificio-sinusoide. Embora o processo de modelação em-pregue seja absolutamente idêntico nos dois casos, as funções de base empregues—sinusoide vs parabola—produzirão sempre curvas diferentes, indepen-dentemente dos parâmetros particulares empregues para cada uma.

Como já deverá ser óbvio, se agora pretendermos criar edifícios com fachadaem curva determinada por uma função f(x) que não seja nem uma sinusóidenem uma parábola, não poderemos empregar as funções anteriores e, primeiro,teremos de definir a função f que implementa essa curva, segundo, teremosde definir a função pontos-f que gera os pontos de f num intervalo e, final-mente, teremos de definir a função edificio-f que invoca a função pontos-fpara criar a região que é a base do edifício. Tudo isto parece excessivamenterepetitivo e, de facto, é. Basta observarmos as semelhanças entre as funçõespontos-sinusoide e pontos-parabola para constatarmos que são muitoidênticas entre si. O mesmo se passa com as funções edificio-sinusoidee edificio-parabola. Logicamente, o mesmo irá acontecer com as novasfunções pontos-f e edificio-f.

Toda esta repetição leva-nos a pensar na possibilidade de abstrairmos osprocessos em questão de modo a que não sejamos obrigados a repetir definiçõesque apenas variam em pequenos detalhes. Para isso, podemos começar porcomparar as definições em questão e perceber onde estão as diferenças. Porexemplo, no caso das funções pontos-sinusoide e pontos-parabola,temos:

(defun pontos-sinusoide (p a omega fi x0 x1 dx)(if (> x0 x1)

()(cons (+xy p x0 (sinusoide a omega fi x0))

17

(pontos-sinusoide p a omega fi (+ x0 dx) x1 dx))))

(defun pontos-parabola (p xv yv d x0 x1 dx)(if (> x0 x1)

()(cons (+xy p x0 (parabola xv yv d x0))

(pontos-parabola p xv yv d (+ x0 dx) x1 dx))))

Assinalámos a itálico as diferenças entre as duas funções e, como podemosver, elas resumem-se aos nomes dos parâmetros e ao nome da função que éinvocada: sinusoide no primeiro caso, parabola no segundo. Sendo osnomes dos parâmetros de uma função visíveis apenas pelo corpo dessa função(i.e., são locais à função), podemos renomea-los desde que o façamos de formaconsistente. Isto quer dizer que as seguintes definições teriam exactamente omesmo comportamento:

(defun pontos-sinusoide (p α β γ x0 x1 dx)(if (> x0 x1)

()(cons (+xy p x0 (sinusoide α β γ x0))

(pontos-sinusoide p α β γ (+ x0 dx) x1 dx))))

(defun pontos-parabola (p α β γ x0 x1 dx)(if (> x0 x1)

()(cons (+xy p x0 (parabola α β γ x0))

(pontos-parabola p α β γ (+ x0 dx) x1 dx))))

Torna-se agora absolutamente óbvio que a única diferença entre as duasfunções está numa invocação que elas fazem, que é sinusoide num caso eparabola no outro.

Ora quando duas funções diferem apenas num nome que usam interna-mente, é sempre possível definir uma terceira função que as generaliza sim-plesmente transformando esse nome num parâmetro adicional.

Imaginemos então que fazemos a seguinte definição, onde f é esse parâmetroadicional:

(defun pontos-funcao (p f alfa beta gama x0 x1 dx)(if (> x0 x1)

()(cons (+xy p x0 (f alfa beta gama x0))

(pontos-funcao p f alfa beta gama (+ x0 dx) x1 dx))))

O aspecto inovador da função pontos-funcao está no facto de receberuma função como argumento, função essa que ficará associada ao parâmetrof. Quando, no corpo da função pontos-funcao é feita uma invocação àfunção f, estamos, na verdade, a fazer uma invocação à função que tiver sidopassada como argumento para o parâmetro f.

Desta forma, a expressão

(pontos-sinusoide p a omega fi 0 lx dx)

é absolutamente idêntica a

18

(pontos-funcao p sinusoide a omega fi 0 lx dx)

Do mesmo modo, a expressão

(pontos-parabola p xv yv d 0 lx dx)

é absolutamente idêntica a

(pontos-funcao p parabola xv yv d 0 lx dx)

A definição da função pontos-funcao é crucial não só para nos permi-tir dispensar as funções pontos-sinusoide e pontos-parabola mas tam-bém para nos permitir criar uma generalização das funções edificio-sinusoidee edificio-parabola. De facto, usando as equivalências anteriores, pode-mos reescrever estas funções na seguinte forma:

(defun edificio-sinusoide (p a omega fi lx dx ly lz)(extrusao

(edificio-plantap (pontos-funcao p sinusoide a omega fi 0 lx dx) lx ly)

lz))

(defun edificio-parabola (p xv yv d lx dx ly lz)(extrusao

(edificio-plantap (pontos-funcao p parabola xv yv d 0 lx dx) lx ly)

lz))

Torna-se agora evidente, pela análise destas duas funções, que é possíveldefinir uma terceira função que as generaliza:

(defun edificio-funcao (p f alfa beta gama lx dx ly lz)(extrusao

(edificio-plantap (pontos-funcao p f alfa beta gama 0 lx dx) lx ly)

lz))

Esta generalização é facilmente compreendida quando constatamos quea função edificio-funcao delega a maior parte do seu esforço na funçãopontos-funcao. Esta, por ser genérica, permite à edificio-funcao sergenérica também, podendo ser usada para gerar edifícios com fachadas comcurvas determinadas pelas funções que pretendermos. No caso de uma si-nusóide, temos, por exemplo:

(edificio-funcao (xy 0 0)sinusoide 0.75 0.5 015 0.4 10 20)

No caso de uma parábola, poderíamos ter:

(edificio-funcao (xy 0 0)parabola 10 0 515 0.5 10 20)

19

Figura 11: Um edifício com uma fachada que acompanha a curva do movi-mento oscilatório amortecido.

Mais importante que o facto de podermos dispensar as funções edificio-sinusoidee edificio-parabola é o facto de, agora, podermos modelar edifícios cujafachada segue qualquer outra curva que pretendamos. Por exemplo, a funçãoque descreve o movimento oscilatório amortecido tem, como definição:

y = ae−bx sin(cx)

ou, em Lisp:

(defun oscilatorio-amortecido (a b c x)(* a (exp (- (* b x))) (sin (* c x))))

Usando a função edificio-funcao é agora trivial definir um edifíciocuja fachada segue a curva do movimento oscilatório amortecido. Por exem-plo, a seguinte expressão

(edificio-funcao (xy 0 0)oscilatorio-amortecido -5 0.1 140 0.4 10 20)

Produz, como resultado da sua avaliação, o edifício representado na Figura 11.

2.2 Funções de Ordem Superior

A função pontos-funcao é um exemplo de uma categoria de funções quedesignamos de ordem superior. Uma função de ordem superior é uma funçãoque recebe outras funções como argumentos ou que devolve outras funçõescomo resultados. No caso da função pontos-funcao ela recebe uma funçãode um parâmetro que ela irá invocar para sucessivos pontos de um intervalo,devolvendo a lista de coordenadas encontradas.

20

As funções de ordem superior são importantes ferramentas de abstracção.Elas permitem abstrair computações em que há uma parte da computação queé comum e uma (ou mais partes) que variam de caso para caso. Usando umafunção de ordem superior, apenas implementamos a parte da computação queé comum, deixando as partes variáveis da computação para serem implemen-tadas como funções que serão passadas nos parâmetros da função de ordemsuperior.

O conceito de função de ordem superior existe há já bastante tempo emmatemática, embora raramente seja explicitamente mencionado. Considere-mos, a título de exemplo, uma função que soma os quadrados de todos osinteiros entre a e b,

∑bi=a i

2:

(defun soma-quadrados (a b)(if (> a b)

0(+ (quadrado a)

(soma-quadrados (1+ a) b))))

_$ (soma-quadrados 1 4)30

Consideremos agora uma outra função que soma as raizes quadradas detodos os inteiros entre a e b,

∑bi=a

√i:

(defun soma-raizes-quadradas (a b)(if (> a b)

0(+ (sqrt a)

(soma-raizes-quadradas (1+ a) b))))

_$ (soma-raizes-quadradas 1 4)6.14626

A mera observação da definição das funções mostra que elas possuem umaestrutura comum que se caracteriza pela seguinte definição:

(defun soma-??? (a b)(if (> a b)

0(+ (??? a)

(soma-??? (1+ a) b))))

Ora esta definição não é mais que uma soma de uma expressão matemáticaentre dois limites, i.e., um somatório

∑bi=a f(i). O somatório é uma abstracção

matemática para uma soma de números descritos por uma expressão matemáticarelativa ao índice do somatório que varia desde o limite inferior até ao limitesuperior. A expressão matemática é, portanto, função do índice do somatório.

O símbolo ??? representa a expressão matemática a realizar dentro do so-matório e que vamos simplesmente transformar num parâmetro, escrevendo:

(defun somatorio (f a b)(if (> a b)

0(+ (f a)

(somatorio f (1+ a) b))))

21

Podemos agora trivialmente avaliar diferentes somatórios:

_$ (somatorio quadrado 1 4)30_$ (somatorio sqrt 1 4)6.14626

Por receber uma função como argumento, o somatório é uma função deordem superior. A função derivada é outro exemplo. A derivada f ′ de umafunção f é uma função que recebe outra função f como argumento e produzoutra função—a função derivada de f—como resultado.

Em geral, as funções de ordem superior surgem porque existem duas oumais funções com uma estrutura semelhante. De facto, a repetição de umpadrão ao longo de várias funções é um forte indicador da necessidade deuma função de ordem superior.

Exercício 2.2.1 Repare-se que, tal como a função somatório, podemos escrever a abstracçãocorrespondente ao produtório (também designado piatório)

Qbi=a f(i). Esta abstracção corre-

sponde ao produto dos valores de uma determinada expressão para todos os inteiros de umintervalo. Escreva uma função Lisp que a implemente.

Exercício 2.2.2 Escreva a função factorial usando o produtório.

Exercício 2.2.3 Quer o somatório, quer o produtório podem ser vistos como casos especiais deuma outra abstracção ainda mais genérica, designada acumulatório. Nesta abstracção, quer aoperação de combinação dos elementos, quer a função a aplicar a cada um, quer o valor inicial,quer o limite inferior, quer a passagem para o elemento seguinte (designado o sucessor), quero limite superior são parâmetros. Defina esta função. Defina ainda o somatório e o produtórioem termos de acumulatório.

2.3 Funções Anónimas

A possibilidade de usarmos funções de ordem superior abre um leque enormede novas aplicações. Por exemplo, se quiseremos calcular os somatórios

10∑i=1

i2 + 3i

100∑i=1

i3 + 2i2 + 5i

não temos de fazer mais do que definir as funções f1(x) = x2 + 3x e f2(x) =x3 + 2x2 + 5x e usá-las como argumento da função somatorio:

(defun f1 (x)(+ (* x x) (* 3 x)))

(defun f2 (x)(+ (* x x x) (* 2 x x) (* 5 x)))

_$ (somatorio f1 1 10)550_$ (somatorio f2 1 100)26204450

22

Como se vê, podemos agora facilmente calcular somatórios de diferentesfunções. No entanto, há um aspecto negativo a salientar: se, para cada so-matório que pretendermos calcular, tivermos de definir a função em questão,iremos “poluir” o nosso ambiente Lisp com inúmeras definições de funçõescuja utilidade será, no máximo, servirem de argumento para o cálculo do so-matório correspondente. Uma vez que cada função tem de ser associada a umnome, teremos também de inventar nomes para todas elas, o que poderá serdifícil, em particular, quando sabemos que estas funções não servem para maisnada. Nos dois últimos exemplos este problema já era visível: os nomes f1 ef2 apenas revelam a dificuldade em arranjar nomes mais expressivos.

Para resolvermos este problema, convém analisar mais em pormenor oconceito de definição de função. Até agora temos referido que, para definirmosuma função, temos de usar uma combinação começada pela palavra defun,seguida do nome da função a definir, seguida da lista de parâmetros, seguidado corpo da função. Por exemplo, para a função x2 = x× x, escrevemos:

(defun quadrado (x) (* x x))

Vimos também que após a definição anterior, o símbolo quadrado ficaassociado a uma função:

_$ quadrado#<USUBR @0e08e500 QUADRADO>

No entanto, vimos também na secção ?? que, para atribuirmos valores avariáveis, podemos usar o operador setq numa combinação que inclua tam-bém o nome da variável seguido da expressão cujo valor pretendemos atribuirà variável. Por exemplo:

(setq fi (/ (+ 1 (sqrt 5)) 2))

Vimos também que após a atribuição anterior, o símbolo fi fica associadoa um valor:

_$ fi1.61803

Deste exemplo decorre que a única diferença entre uma definição de funçãoe uma atribuição de valor se resume à forma como se obtém o valor que éatribuido num caso e noutro. Na atribuição, o valor é o resultado da avali-ação de uma expressão. Na definição de função, o valor é uma função quese constrói a partir de uma descrição de uma lista de parâmetros e de umcorpo de função. Isto leva-nos a pensar que se fosse possível termos umaexpressão cuja avaliação produzisse uma função, então seria possível definirfunções usando simplesmente o operador de atribuição. Por exemplo no casoda função quadrado, se for λ essa expressão, deveria ser possível escrever(setq quadrado λ).

Se a expressão (setq quadrado λ) associa ao símbolo quadrado a funçãocriada pela avaliação da expressão λ, o que será então a avaliação da expressão

23

λ? Obviamente, tem de ser uma função, mas, como não está ainda associada anenhum nome, é o que se denomina por função sem nome ou função anónima.Note-se que uma função anónima é uma função como qualquer outra, mastem a particularidade de não estar associada a nenhum nome.

Falta-nos ainda conhecer a forma das expressões λ. Elas possuem umasintaxe semelhante à da definição de funções, mas omitem o nome da função(logicamente) e substituem o símbolo defun por. . . lambda, i.e.:3

(lambda (parâmetro1 ... parâmetron)corpo)

Qualquer expressão com a forma anterior, quando avaliada, produz umafunção anónima. Estas expressões designam-se, em Lisp, por expressões lambda.Reparemos agora na seguinte interacção:

_$ (lambda (x) (* x x))#<USUBR @07c02294 -lambda->_$ (setq quadrado (lambda (x) (* x x)))#<USUBR @07c0d9c4 -lambda->_$ (quadrado 3)9

Como se vê, a avaliação da expressão lambda devolve algo cuja represen-tação externa é idêntica à de uma qualquer função, com a diferença de queo nome da função foi substituido pela palavra -lambda- para indicar que afunção é anónima e foi produzida a partir de uma expressão lambda. Quandoassociamos a função anónima a um símbolo qualquer, esse símbolo passa adesignar a função, podendo ser usado como se tivesse sido definido usandodefun. Na prática, a definição de funções via defun

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

é equivalente a:4

(setq nome (lambda (parâmetro1 ... parâmetron) corpo))

Esta equivalência é facilmente testável através da redefinição de funçõesque, anteriormente, tinham sido definidas usando a forma defun e que, agora,podemos redefinir usando a formas setq e lambda. O exemplo anteriordemonstrou essa possibilidade para a função quadrado mas ela existe paraqualquer função. Por exemplo, a função que calcula a área de um círculo tantopode ser definida por:

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

como pode ser definida por:

3A utilização que fizemos do símbolo λ não foi inocente. Ele deriva das origens matemáticasdo conceito de função anónima: o cálculo λ, um modelo matemático para funções computáveis,i.e., funções cuja invocação se pode avaliar mecanicamente.

4Na realidade, a equivalência não é total, pois existem algumas diferenças subtis que, demomento, são irrelevantes.

24

(setq area-circulo(lambda (raio)

(* pi (quadrado raio))))

Embora do ponto de vista sintático, a forma defun seja equivalente a umacombinação de formas setq e lambda, existe uma diferença semântica comimplicações importantes: a forma defun não avalia nenhum dos seus argu-mentos, enquanto que a forma setq avalia o seu segundo argumento. Istopermite que a forma setq possa definir funções de formas mais sofisticadas.

A utilização de funções anónimas tem ainda outra vantagem que se tornaevidente quando analisamos a função pontos-funcao:

(defun pontos-funcao (p f alfa beta gama x0 x1 dx)(if (> x0 x1)

()(cons (+xy p x0 (f alfa beta gama x0))

(pontos-funcao p f alfa beta gama (+ x0 dx) x1 dx))))

Como vimos, para gerarmos uma lista de pontos de, por exemplo, umasinusóide, podemos invocar esta função da seguinte forma:

(pontos-funcao (xy 0 0)sinusoide 0.75 0.5 00 15)

Notemos que, por ter sido definida como uma generalização das funçõespontos-sinusoide e pontos-parabola, a função pontos-funcao, paraalém de ter introduzido a função f como parâmetro, generalizou também osparâmetros a, omega e fi da função pontos-sinusoide e xv, yv e d dafunção pontos-parabola, chamando-lhes, respectivamente, alfa, beta egama. Acontece que estes parâmetros nunca são alterados durantes as in-vocações recursivas realizadas pela função pontos-funcao. Na verdade, afunção passa esses parâmetros de invocação recursiva em invocação recursivaapenas porque eles são necessários para a invocação da função f. Imaginemosagora que, ao invés de passarmos esses parâmetros, eles estivessem associadosà própria função f que tínhamos passado. Neste caso, poderíamos reescrevera função pontos-funcao na seguinte forma:

(defun pontos-funcao (p f x0 x1 dx)(if (> x0 x1)()(cons (+xy p x0 (f x0))

(pontos-funcao p f (+ x0 dx) x1 dx))))

Com esta nova definição, a invocação anterior teria de ser reescrita naforma:

(pontos-funcao (xy 0 0)(lambda (x) (sinusoide 0.75 0.5 0 x))0 15)

25

Figura 12: Curvas geradas pela função pontos-funcao. De cima para baixo,temos uma sinusóide, uma exponencial invertida e uma sinusóide amortecida.

Embora não pareça ser um ganho substancial, a reescrita da função pontos-funcaotem uma vantagem considerável: ela permite a utilização de quaisquer funçõesde base, independentemente do número de parâmetros que elas precisam: setiverem apenas um parâmetro, podem ser usadas directamente, caso contrário,podemos “envolvê-las” com uma função anónima de um só parâmetro que in-voca a função pretendida com todos os argumentos necessários. Isto faz comque a função pontos-funcao fique ainda mais genérica, tal como é visívelnos seguintes exemplos:

(spline-pontos(pontos-funcao (xy 0 6)

sin0 4*pi 0.2))

(spline-pontos(pontos-funcao (xy 0 3)

(lambda (x)(- (expt (/ x 10) 3)))

0 4*pi 0.5))

(spline-pontos(pontos-funcao (xy 0 0)

(lambda (x)(oscilatorio-amortecido 1.5 0.4 4 x))

0 4*pi 0.05))

que geram as curvas representadas na Figura 12.A partir do momento em que é possível “esconder” os parâmetros adi-

cionais de uma função dentro de uma lambda, podemos simplificar tambéma função edificio-funcao, eliminando os parâmetros alfa, beta e gamaque apenas eram usados para serem passados à função argumento:

26

(defun edificio-funcao (p f lx dx ly lz)(extrusao

(edificio-plantap (pontos-funcao p f 0 lx dx) lx ly) lz))

Usando esta nova versão podemos facilmente modelar edifícios com asfachadas que pretendermos sem necessitar de definir quaisquer funções adi-cionais.

Exercício 2.3.1 Sabe-se que a soma 81·3 + 8

5·7 + 89·11 + · · · converge (muito lentamente) para

π. Usando a função acumulatorio definida no exercício anterior, defina a função que calculauma aproximação de π até ao n-ésimo termo da soma. Determine uma aproximação de π atéao termo 2000.

2.4 Funções Anónimas e Variáveis Locais

Dissémos, na discussão anterior sobre funções anónimas e funções com nome,que(defun nome (parâmetro1 ... parâmetron) corpo)

é equivalente a(setq nome (lambda (parâmetro1 ... parâmetron) corpo))

No entanto, já na secção ?? tínhamos referido que a sintaxe completa dadefinição de uma função incluia a possibilidade de introdução de variáveislocais à função, usando a sintaxe(defun nome (parâmetro1 ... parâmetron

/ variável1 ... variávelm)corpo)

Como seria de esperar, a equivalência anterior é generalizável à definiçãode funções com variáveis locais, i.e., também as funções anónimas podem tervariáveis locais. Assim, a sintaxe completa para a definição de funções anóni-mas é a seguinte:

(lambda (parâmetro1 ... parâmetron

/ variável1 ... variávelm)corpo)

Como resulta da secção anterior, quanto menos variáveis livres uma funçãotiver menos hipóteses de conflito existem quando ela é usada como argumentode funções de ordem superior. Por este motivo, mesmo em funções anónimas,devemos empregar variáveis locais sempre que possível.

2.5 Âmbito e Duração

A partir do momento em que podemos escrever expressões lambda (e obterfunções anónimas), podemos mais facilmente utilizar funções de ordem supe-rior sem ter de definir explicitamente as funções que são usadas como argu-mentos. Por exemplo, para os dois somatórios que referimos anteriormente

10∑i=1

i2 + 3i

27

Figura 13: Gráfico sobreposto das funções quadrática f1(x) = 0.4x2 − 2.5x+ 3e cúbica f2(x) = 0.5x3 − 4.5x2 + 11.5x− 7.5 no intervalo [0.7, 5.3].

100∑i=1

i3 + 2i2 + 5i

não necessitamos de definir explicitamente as funções f1(x) = x2+3x e f2(x) =x3 + 2x2 + 5x pois podemos simplesmente usar as expressões lambda equiva-lentes como argumento da função somatorio:

_$ (somatorio (lambda (x) (+ (* x x) (* 3 x))) 1 10)550_$ (somatorio (lambda (x) (+ (* x x x) (* 2 x x) (* 5 x))) 1 100)26204450

As expressões lambda são também úteis na representação gráfica de funções.Por exemplo, se quisermos representar graficamente as funções quadráticaf1(x) = 0.4x2 − 2.5x + 3 e cúbica f2(x) = 0.5x3 − 4.5x2 + 11.5x − 7.5 nointervalo [0.7, 5.3], ao invés de termos de definir estas funções cujo significadoseria muito pouco claro, podemos simplesmente escrever:

(spline-pontos(pontos-funcao (lambda (x)

(+ (* 0.4 x x) (* -2.5 x) 3))0.7 5.3 0.1))

(spline-pontos(pontos-funcao (lambda (x)

(+ (* 0.5 x x x) (* -4.5 x x) (* 11.5 x) -7.5))0.7 5.3 0.1))

e gerar o gráfico que apresentamos na Figura 13.De igual modo, através da utilização de expressões lambda podemos sim-

plificar algumas das funções que definimos anteriormente. Por exemplo, afunção pontos-sinusoide, cuja definição era:

28

(defun pontos-sinusoide (p a omega fi x0 x1 dx)(if (> x0 x1)

()(cons (+xy p x0 (sinusoide a omega fi x0))

(pontos-sinusoide p a omega fi (+ x0 dx) x1 dx))))

pode passar a ser simplesmente:

(defun pontos-sinusoide (p a omega fi x0 x1 dx)(pontos-funcao

(lambda (x) (sinusoide a omega fi x0)) x0 x1 dx))

Reparemos que, nesta definição da função pontos-sinusoide, a expressãolambda empregue faz referência a variáveis a, omega e fi, que não fazemparte dos parâmetros da função anónima correspondente.

Como vimos na secção ??, variáveis com esta característica dizem-se livrese são tratadas de forma diferente em diferentes dialectos de Lisp, em particu-lar no que diz respeito à duração de uma variável. No caso do Auto Lisp, asvaráveis locais (incluindo os parâmetros da funções) possuem duração dinâmica,i.e., apenas podem ser referidas durante a invocação das funções que as intro-duzem. Lisps modernos optam por empregar a duração indefinida, em que umavariável pode ser referida a partir do momento em que é criada.

Para além da duração, existe um segundo conceito relevante para com-preendermos uma variável: o âmbito. O âmbito de uma variável é a regiãotextual onde podemos referenciar a variável. Mais uma vez, diferentes dialec-tos de Lisp empregam diferentes estratégias para o âmbito das variáveis. Nocaso do Auto Lisp, emprega-se o chamado âmbito indefinido, que significa quepodemos referenciar uma variável a partir de qualquer ponto do programa(mas apenas durante a sua duração). Lisps modernos consideram esta abor-dagem problemática e preferem o chamado âmbito léxico, em que uma variávelapenas pode ser referida na região textual da forma que a introduz. NessesLisps (mas não no Auto Lisp) um parâmetro de uma função, por exemplo,apenas pode ser referido dentro dessa função.

O tratamento diferente que os diferentes Lisps dão às variáveis revela-seno âmbito e na duração das variáveis. O caso particular da linguagem AutoLisp, que emprega duração dinâmica e âmbito indefinido, denomina-se âmbitodinâmico.

Modernamente, considera-se que o âmbito léxico é preferível ao dinâmicoe que a duração indefinida é preferível à dinâmica. Infelizmente, aquando dainvenção do Auto Lisp, o âmbito léxico e a duração indefinida eram mal com-preendidos e evitavam-se por se julgar que tinham impactos muito negativosna performance. O Visual Lisp, sendo muito posterior ao Auto Lisp, poderia terresolvido esse problema mas antes preferiu manter a compatibilidade com oAuto Lisp.

Os conceitos de âmbito e duração são importante para compreendermos ocomportamento do Auto Lisp quando confrontado com variáveis livres. Con-sideremos, a título de exemplo, as duas seguintes funções:

(defun f1 (x)(f2))

29

(defun f2 ()x)

e a seguinte interacção:

_$ (f1 123)123

Para percebermos a validade deste resultado é necessário analisar o âm-bito e a duração das referências. Obviamente, quando a função f1 foi invo-cada com o argumento 123, o parâmetro x ficou associado a este número e,de seguida, a função f2 foi invocada (sem argumentos). Esta última funçãolimitou-se a devolver o valor da variável x que, para f2, é simplesmente umavariável livre. Do ponto de vista do âmbito, uma vez que o Auto Lisp em-prega âmbito indefinido, a referência que f2 faz a x é legítima. Uma vez queo Auto Lisp emprega duração dinâmica e existe, no momento da invocaçãode f2, uma associação entre x e 123, isso quer dizer que, do ponto de vistada duração, a referência a x também é legítima. Está assim justificado o bomcomportamento do programa.

No entanto, existe ainda uma subtileza a considerar. Vejamos a seguintevariante do programa anterior:

(defun f1 (x)(f2 (+ x 1)))

(defun f2 (x)(f3))

(defun f3 ()x)

Se repetirmos para este novo exemplo a análise que fizemos atrás, iremosfacilmente concluir que o programa também é legítimo. De facto, se invo-carmos f1 com um número qualquer, f2 é também invocada (com o sucessordesse número) e, finalmente, f3 é invocada. Nesse momento, é feita uma refer-ência a x, referência essa que é válida pois existe uma associação entre x e umvalor. O mais interessante é que não existe só uma associação entre x e umvalor; existem duas. A primeira é a que foi estabelecida aquando da invocaçãode f1 e a segunda é a que foi estabelecida aquando da invocação de f2. Oproblema agora é: a qual delas é que f3 se refere?

Para respondermos à pergunta podemos simplesmente testar o programa:

_$ (f1 1)2

Como deverá ser evidente, este resultado só é possível se a referência quef3 faz a x disser respeito à última associação que foi feita a x e, de facto, essaé uma característica do âmbito dinâmico: o valor de uma variável é obtidopela última associação que tiver sido feita a essa variável. Todas as outrasassociações para essa variável ficam obscurecidas pela associação mais recente.

30

Note-se que esta regra não invalida que a duração das variáveis seja, comosempre, dinâmica. Para confirmarmos isto, basta-nos fazer uma pequena mod-ificação ao programa anterior para que a primeira função faça também umareferência a x:

(defun f1 (x)(+ (f2 (+ x 1))

x))

(defun f2 (x)(f3))

(defun f3 ()x)

Neste caso, quando testamos o programa, obtemos:

_$ (f1 1)3

Uma vez que já sabemos que a invocação de f2 devolve 2, este resultadosó é possível se o valor de x dentro de f1 ainda for o valor original 1. De facto,uma vez que a associação que f2 faz a x é de duração dinâmica, quando ainvocação de f2 termina, essa associação é eliminada e a “última” associaçãoainda existente é a que f1 estabeleceu, i.e., com x a valer 1.

2.6 Funções de Ordem Superior e Variáveis Livres

Em geral, o âmbito e duração de variáveis é irrelevante pois, na maioria doscasos, os programas comportam-se da mesma forma independentemente dea linguagem empregar âmbito léxico ou indefinido, ou duração dinâmica ouindefinida.

No entanto, a situação muda radicalmente no caso de funções de ordem su-perior que recebem ou devolvem funções com variáveis livres. Para perceber-mos o problema, consideremos de novo a função somatorio cuja definiçaoera:

(defun somatorio (f a b)(if (> a b)0(+ (f a)

(somatorio f (1+ a) b))))

Imaginemos agora que queremos definir uma função para calcular o so-matório da funcão do segundo grau f(x) = ax2 + bx+ c para todos os inteirosentre um limite inferior um superior. Para isso, definimos:

(defun soma-segundo-grau (a b c lim-inf lim-sup)(somatorio(lambda (x)

(+ (* a (quadrado x)) (* b x) c))lim-inflim-sup))

31

Para testar esta função consideremos∑1

x=−1 10x2 + 5x:

_$ (soma-segundo-grau 10 5 0 -1 1)0

Obviamente, há algo que não está certo pois, na verdade,∑1

x=−1 10x2 + 5x =10− 5 + 0 + 10 + 5 = 20. Qual será o problema?

Para o percebermos, temos de ensaiar a avaliação da expressão. Quandosoma-segundo-grau é invocada, é estabelecida uma associação entre a e10, entre b e 5, entre c e 0, entre lim-inf e -1 e entre lim-sup e 1. Emseguida, é invocada a função somatorio com três argumentos: o primeiroé uma função anónima que faz referência aos valores de a, b e c, ficandoassociada ao parâmetro f, o segundo e o terceiro são os limites -1 e 1, queficam associados aos parâmetros a e b da função somatório e é nesse mo-mento que começam os problemas. Quando, na função somatorio, é invo-cada a função f (passando-lhe o primeiro valor do intervalo, -1), isso im-plica a avaliação do corpo da função anónima que lhe está associada, i.e.,(+ (* a (quadrado x)) (* b x) c), com x associado a -1. O problemaé que os nomes a e b estão, nesse momento, ainda associados a -1 e 1, respec-tivamente, tendo sido obscurecidas as ligações a 10 e 5, respectivamente. Nasinvocações seguintes, b manter-se-á associado a 1 e a irá estar associado a 0 e,depois, a 1.

Na prática, a avaliação do somatório computa (−1·(−1)2+1·(−1)+0)+(0·(0)2 +1 ·0+0)+(1 · (1)2 +1 ·1+0) = −2+2 = 0. Claramente, houve um prob-lema introduzido pelo âmbito dinâmico e que tem a ver, exclusivamente, como facto de se estar a invocar uma função que possui variáveis livres num con-texto onde as anteriores associações dessas variáveis ficaram obscurecidas.5

Este género de problemas é, infelizmente, muito difícil de detectar, sendoeste um dos motivos que leva os modernos dialectos de Lisp a evitar o âmbitodinâmico e a optar pelo âmbito léxico. No entanto, dois dos dialectos maisusados actualmente—o EmacsLisp e o Auto Lisp—continuam, por motivoshistóricos, a empregar o âmbito dinâmico.

Uma vez que a utilização de funções de ordem superior traz inúmeras van-tagens à modularidade dos nossos programas, é importante sabermos codi-ficar essas funções de forma a não interferirem no correcto funcionamento dasfunções por elas invocadas. Para isso, uma solução muito simples consisteem empregar nomes pouco usuais para os parâmetros e variáveis locais dasfunções de ordem superior. Por exemplo, consideremos a seguinte definiçãoda função somatório:

(defun somatorio (%%**f**%% %%**a**%% %%**b**%%)(if (> %%**a**%% %%**b**%%)0(+ (%%**f**%% %%**a**%%)

(somatorio %%**f**%% (1+ %%**a**%%) %%**b**%%))))

Com esta definição, já obtemos o resultado correcto:5Historicamente, este problema ficou conhecido como o problema do argumento funcional

ou, no original, funarg problem.

32

_$ (soma-segundo-grau 10 5 0 -1 1)20

Como se vê na definição anterior, os nomes dos parâmetros são tão estran-hos que é razoável admitir que ninguém, no seu perfeito juízo, irá definir umafunção que tenha uma variável livre chamada %%**f**%%, %%**a**%% ou%%**b**%%. Obviamente, esta nomenclatura dificulta enormemente a com-preensão da função somatorio pelo que deve ser usada com alguma parcimó-nia. Uma outra abordagem que simplifica bastante o problema será consideraruma convenção mais simples de escrita de nomes mas considerá-la de uso ex-clusivo por funções de ordem superior. Por exemplo, podemos considerar quetodos os nomes começados por _ (underscore) estão reservados para funçõesde ordem superior. Neste caso, a função somatório ficará com a forma:

(defun somatorio (_f _a _b)(if (> _a _b)

0(+ (_f _a)

(somatorio _f (1+ _a) _b))))

Desde que se garanta que nenhuma função passada como argumento desomatorio empregue também esta notação, nunca ocorrerá obscurecimentoinadvertido de associações.

Infelizmente, quando temos funções de ordem superior que invocam out-ras funções de ordem superior a possibilidade de conflito de nomes continuaa existir. Neste caso, uma última convenção poderá ajudar: preceder os nomesdos parâmetros do nome da função ou, se este nome for demasiado grande, deuma sua abreviatura inequívoca. Segundo esta abordagem, a função somatoriopoderá ter a seguinte definição:

(defun somatorio (s:f s:a s:b)(if (> s:a s:b)

0(+ (s:f s:a)

(somatorio s:f (1+ s:a) s:b))))

Na mesma linha de raciocínio, a função pontos-funcao, por ser de or-dem superior, deverá ser redefinida para:

(defun pontos-funcao (pf:f pf:x0 pf:x1 pf:dx)(if (> pf:x0 pf:x1)

(list)(cons (xy pf:x0 (pf:f pf:x0))

(pontos-funcao pf:f (+ pf:x0 pf:dx) pf:x1 pf:dx))))

33

2.7 Representação Paramétrica

Até agora, apenas temos produzido curvas descritas por funções na forma y =f(x). Estas funções dizem-se na forma Cartesiana.

Uma outra forma de representar matematicamente uma curva é através deequaçõesF (x, y) = 0. Esta forma, dita implícita, é mais geral que a anterior que,na verdade, não é mais que a resolução desta em relação à ordenada y. Comoexemplo de uma curva descrita na forma implícita consideremos a equaçãox2 + y2 − r2 = 0 que descreve uma circunferência de raio r com centro em(0, 0). Infelizmente, esta segunda forma de representar curvas não é tão útilcomo a anterior pois nem sempre é trivial (ou possível) resolver a equação emrelação à ordenada.6 Por exemplo, no caso da circunferência, o melhor queconseguimos fazer é produzir duas funções:

y(x) = ±√r2 − x2

Existe, no entanto, uma terceira forma de representação de curvas que setorna particularmente útil: a forma paramétrica. A forma paramétrica baseia-sena ideia de que a curva pode ser percorrida por um ponto cuja posição evoluiao longo do tempo. O tempo, aqui, é meramente um parâmetro que determinaa posição do ponto sobre a curva. Retomando o caso da circunferência comcentro em (0, 0), a sua descrição paramétrica será

x(t) = r cos t

y(t) = r sin t

Como é óbvio, para que o ponto de coordenadas (x, y) possa percorrer toda acircunferência, basta que o parâmetro t varie no intervalo [0, 2π].

As equações anteriores denominam-se as equações paramétricas da curva.Se, numa representação paramétrica, eliminarmos o parâmetro, naturalmenteencontraremos a equação original da curva. Por exemplo, no caso da circun-ferência, se somarmos os quadrados das equações paramétricas obtemos

x2 + y2 = r2(cos2 t+ sin2 t) = r2

Tal como acontecia com a resolução da equação de uma curva F (x, y) = 0em relação à ordenada y = f(x), nem sempre é fácil (ou possível) trans-formar equações paramétricas x = Φ(t), y = Ψ(t) numa função f tal quey = f(x). Felizmente, para a representação gráfica da curva, essa transfor-mação é desnecessária pois a representação paramétrica é perfeitamente uti-lizável e, frequentemente, preferível.7

Para vermos um exemplo prático, consideremos a espiral de Arquimedes: acurva descrita por um ponto que se move com velocidade constante v ao longo

6Excepto no caso de rectas, cuja equação geral é ax+ by + c = 0, b 6= 0 e onde é óbvio que aresolução em relação à ordenada é y = −ax+c

b.

7Na prática, a representação de uma curva na forma y = f(x) é uma simplificação trivial darepresentação paramétrica x = t, y = f(t).

34

de um raio que gira em torno de um pólo com velocidade angular constanteω. Em coordenadas polares, a equação da espiral de Arquimedes tem a forma

ρ =v

ωθ

ou, com α = vω ,

ρ = αθ

Quando convertemos a equação anterior para coordenadas rectangulares, us-ando as fórmulas

x = ρ cos θy = ρ sin θ

obtemos x(θ) = αθ cos θy(θ) = αθ sin θ

que, como se pode ver, é uma descrição paramétrica em função de θ.Mais simples ainda é a conversão directa, para a forma paramétrica, da

representação polar da espiral de Arquimedes. Basta-nos substituir θ por t eacrescentar mais uma equação que expressa esta substituição, ou seja

ρ(t) = αt

θ(t) = t

Embora tenhamos explicado a representação paramétrica em termos decoordenadas bidimensionais, a extensão ao espaço tridimensional é trivial.Basta, para isso, considerar cada ponto tridimensional função de um parâmetro,i.e., (x, y, z) = (Φ(t),Ψ(t),Γ(t)).

2.7.1 Computação de Funções Paramétricas

Uma vez que a representação paramétrica simplifica substancialmente a con-strução de curvas, pretendemos agora definir em Auto Lisp uma função parametricaque, a partir da descrição paramétrica de uma curva, produz o conjunto depontos que a função spline-pontos necessita para traçar o gráfico corre-spondente. Para simplificar, vamos considerar como parâmetros da funçãoparametrica, não duas funções x = Φ(t), y = Ψ(t) mas sim uma só função(x, y) = Ω(t) que calcula directamente as coordenadas pretendidas. Esta abor-dagem tem a vantagem de ser generalizável, sem quaisquer alterações, paracurvas no espaço tridimensional (x, y, z) = Ω(t).

Tal como fizemos anteriormente, para gerar os pontos vamos especificaros limites do intervalo do parâmetro [t0, t1] e o incremento progressivo do seuvalor ∆t. A definição é a seguinte:

(defun parametrica (f t0 t1 dt)(if (> t0 t1)

()(cons (f t0)

(parametrica f (+ t0 dt) t1 dt))))

35

Tendo em conta o potencial conflito de nomes existente nas funções de or-dem superior em Auto Lisp (descrito na secção 2.6), é preferível “proteger” osparâmetros da função, produzindo a seguinte versão alternativa:

(defun parametrica (p:f p:t0 p:t1 p:dt)(if (> p:t0 p:t1)

()(cons (p:f p:t0)

(parametrica p:f (+ p:t0 p:dt) p:t1 p:dt))))

A computação das coordenadas da espiral de arquimedes pode agora serfeita trivialmente, usando:8

(defun espiral-arquimedes (p alfa t0 t1 dt)(parametrica

(lambda (ti)(+xy p

(* alfa ti (cos ti)))(* alfa ti (sin ti)))

t0t1dt))

Outra possibilidade, ainda mais simples, é explorar a criação de pontos emcoordenadas polares (usando o construtor +pol). Neste caso, a definição dafunção espiral-arquimedes fica simplesmente:

(defun espiral-arquimedes (p alfa t0 t1 dt)(parametrica

(lambda (ti)(+pol p (* alfa ti) ti))

t0t1dt))

A Figura 14 mostra três espirais de Arquimedes desenhadas a partir dasseguintes invocações:

(spline-pontos(espiral-arquimedes (xy 0 0) 2.0 0 (* 4 pi) 0.1))

(spline-pontos(espiral-arquimedes (xy 50 0) 1.0 0 (* 6 pi) 0.1))

(spline-pontos(espiral-arquimedes (xy 100 0) 0.2 0 (* 36 pi) 0.1))

8Nesta definição, aproveitamos para tornar o centro da espiral como um parâmetro p queopera uma simples translação.

36

Figura 14: Espirais de Arquimedes. Da esquerda para a direita, os parâmetrossão α = 2, t ∈ [0, 4π], α = 1, t ∈ [0, 6π], α = 0.2, t ∈ [0, 36π].

2.7.2 Erros de Arredondamento

Embora muito útil, a função parametrica tem um problema: quando o in-cremento dt não é um número inteiro, a sua adição sucessiva vai acumulandoerros de arrendondamento, o que pode provocar um comportamento bizarro.Para exemplificarmos a situação, consideremos duas enumerações dos pontosdo intervalo [0, 1], a primeira com um incremento de 1

10 e a segunda com umincremento de 1

100 :

_$ (parametrica (lambda (x) x) 0 1 (/ 1.0 10))(0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0)_$ (parametrica (lambda (x) x) 0 1 (/ 1.0 100))(0 0.01 0.02 0.03 0.04 0.05 ... 0.94 0.95 0.96 0.97 0.98 0.99)

Obviamente, há ali um problema: ambos as enumerações deveriam ter-minar no limite superior do intervalo 1.0 mas, aparentemente, a segundaenumeração terminou mais cedo que o que seria expectável, não conseguindoproduzir o último ponto.

O problema resulta do facto de que 110 e 1

100 não são representáveis comexactidão em notação binária. Na verdade, a fracção 1

10 é representada porum número que é ligeiramente inferior a 0.1, enquanto que a fracção 1

100 érepresentada por um número ligeiramente superior a 0.01. A consequênciaé que uma soma suficientemente grande destes números acaba por acumularum erro que faz com que o último ponto, no caso da fracção 1

100 , seja, afinal,superior ao limite, pelo que é descartado.9

Por estes motivos, é preferível evitar o uso da função parametrica quandoos argumentos t0, t1 e dt não são números inteiros. Para lidar correctamentecom números reais, devemos usar outra abordagem que se baseie em produziro número de pontos realmente pretendido evitando adições sucessivas. Paraisso, ao invés de usarmos o incremento como parâmetro, iremos antes usar onúmero de pontos pretendidos.

9Este fenómeno tem sido causa de inúmeros problemas no mundo da informática. Desdeerros nos sistemas de defesa anti-míssil ao cálculo errado de índices bolsistas, a história dainformática está repleta de exemplos catastróficos causados por erros de arrendondamento.

37

Na sua forma actual, a função parametrica gera os pontos ti a partir doslimites t0 e t1 e do incremento ∆t a partir de

ti = t0 + ∆t + ∆t + · · · + ∆t︸ ︷︷ ︸i vezes

ti = t0 +i∑

j=0

∆t

O problema da fórmula anterior é, como vimos, a potencialmente grandeacumulação de erros que ocorre ao somarmos um elevado número de vezeso ligeiro erro existente no valor de ∆t. Para minimizarmos essa acumulaçãode erros temos de encontrar uma formula alternativa que evite o termo ∆t.Uma possibilidade atraente é considerar, não um incremento ∆t, mas simum número n de incrementos ∆t que interessa computar. Obviamente, essenúmero n relaciona-se com ∆t pela equação

n =t1 − t0

∆t

Consequentemente, temos também

∆t =t1 − t0n

Substituindo na equação anterior, temos

ti = t0 +i∑

j=0

∆t ≡

ti = t0 +i∑

j=0

t1 − t0n

ti = t0 +t1 − t0n

i∑j=0

1 ≡

ti = t0 +t1 − t0n

i

O aspecto fundamental da última equação é que ela já não correspondea uma soma de i termos onde pode ocorrer uma acumulação de erros dearredondamento, mas sim a uma “função” f(i) = t1−t0

n i de i, em que i nãoacarreta qualquer erro pois é simplesmente um número inteiro que evoluidesde 0 até n. A partir deste número é agora possível calcular o valor de tique, embora possa ter os inevitáveis erros de arrendondamento causados pelautilização de reais, não terá uma acumulação desses erros.

Com base nesta última fórmula é agora fácil escrever uma nova funçãoparametrica-n que computa directamente o valor da função f no pontoti, sem adições sucessivas, a partir do número n de pontos pretendidos nointervalo [t0, t1]:

38

(defun parametrica-n (pn:f pn:t0 pn:t1 pn:n)(parametrica

(lambda (pn:i)(pn:f (+ pn:t0 (/ (* pn:i (- pn:t1 pn:t0)) 1.0 pn:n))))

0pn:n1))

Como é natural, esta nova definição não elimina erros de arredondamento,mas evita a sua acumulação.

2.7.3 Precisão

Como vimos anteriormente, a precisão da curva produzida pela função parametricaé determinada pelo incremento ∆t que é usado na evolução do parâmetro tentre t0 e t1. Quanto mais pequeno for ∆t, maior será o número de pontosda curva n = t1−t0

∆te, consequentemente, maior será a precisão da curva. Já

no caso da função parametrica-n, como trabalhamos directamente com onúmero de pontos n, quanto maior for este número, menor será o incremento∆t = t1−t0

n e, consequentemente, maior será a precisão da curva.Em qualquer caso, é necessário termos em conta que a relação entre o

número de pontos n e o incremento ∆t depende também do tamanho do inter-valo [t0, t1] e que quanto maior for esse intervalo, mais pontos serão necessários.Para percebermos o impacto deste intervalo, vamos analisar um exemplo con-creto: a curva Borboleta proposta pelo matemático Temple H. Fay. Esta curvadefine-se pela equação em coordenadas polares

r = esin θ − 2 cos(4θ) + sin5

(2θ − π

24

)À semelhança do que fizemos anteriormente, vamos considerar a curva

relativamente a um ponto de partida P , dentro de um intervalo de variaçãodo parâmetro independente t ∈ [t0, t1].

(defun curva-borboleta (p t0 t1 n)(parametrica-n

(lambda (ti)(+pol p

(+ (exp (sin ti))(* -2 (cos (* 4 ti)))(expt (sin (/ (- (* 2 ti) pi) 24)) 5))

ti))t0t1n))

Para o desenho desta curva falta-nos agora determinar o valor adequadodo parâmetro n. Para isso, é importante percebermos que o período da curvaBorboleta é de 24π, sendo a curva completa gerada para t ∈ [0, 24π]. Umavez que este período é relativamente grande, o número n de pontos a empre-gar deverá ser suficiente para que se consiga reproduzir fielmente a curva e

39

Figura 15: A curva Borboleta produzida para valores crescentes do número nde pontos.

é precisamente aqui que surge a maior dificuldade: sem conhecer a forma dacurva, é difícil estimar qual o melhor valor para n. Se o valor de n for de-masiado baixo, a curva não será representada com fidelidade, em particular,nos locais em que existem curvaturas muito acentuadas; se o valor for demasi-ado alto, maior será a necessidade de recursos computacionais. Na prática, énecessária alguma experimentação para perceber qual o melhor valor.

Esta necessidade de experimentação relativamente ao valor do número depontos a empregar está bem patente na Figura 15 que mostra as curvas Borbo-leta desenhada para os seguinte crescentes valores de n:

(spline-pontos (curva-borboleta (xy 0 10) 0 (* 24 pi) 10))(spline-pontos (curva-borboleta (xy 10 10) 0 (* 24 pi) 20))(spline-pontos (curva-borboleta (xy 20 10) 0 (* 24 pi) 40))(spline-pontos (curva-borboleta (xy 30 10) 0 (* 24 pi) 80))(spline-pontos (curva-borboleta (xy 40 10) 0 (* 24 pi) 160))(spline-pontos (curva-borboleta (xy 0 0) 0 (* 24 pi) 320))(spline-pontos (curva-borboleta (xy 10 0) 0 (* 24 pi) 640))(spline-pontos (curva-borboleta (xy 20 0) 0 (* 24 pi) 1280))(spline-pontos (curva-borboleta (xy 30 0) 0 (* 24 pi) 2560))(spline-pontos (curva-borboleta (xy 40 0) 0 (* 24 pi) 5120))

Como podemos verificar, quando o número de pontos é insuficiente, ascurvas produzidas podem ser grotescas distorções da realidade. Por este mo-tivo, devemos ter um particular cuidado na escolha do valor adequado paraeste parâmetro.

Exercício 2.7.1 Redefina a função espiral-arquimedes que calcula uma lista de pontos poronde passa uma espiral de Arquimedes mas empregando a função parametrica-n. Ao invésdo incremento ∆t, a sua função deverá antes receber o número de pontos n.

Exercício 2.7.2 Defina a função parede-espiral-arquimedes que, a partir de uma espes-sura e altura e ainda dos parâmetros de uma espiral de Arquimedes, cria uma parede em espi-ral, tal como se apresenta na seguinte imagem:

40

Exercício 2.7.3 Usando a função parametrica-n defina a função cilindros-espiral-arquimedesque constrói n cilindros de raio r e altura h e os coloca ao longo de uma espiral de arquimedes,de acordo com os parâmetros desta espiral, tal como se apresenta na seguinte figura:

Exercício 2.7.4 A investigação em Análise Numérica tem produzido algumas soluções alterna-tivas para o problema da acumulação de erros. Uma dessas soluções é o algoritmo de soma deKahan. Consulte esse algoritmo e implemente-o de modo a que ele seja utilizável pela funçãoparametrica quando o incremento ∆t não é um número inteiro.

É importante percebermos que o problema de acumulação de erros de ar-rendondamento quando o incremento não é directamente representável pelocomputador não é exclusivo da função parametrica: também a função enumeraterá o mesmo comportamento.10 Para resolvermos este problema, basta-nosempregar a mesma solução que adoptámos para a função parametrica: deixarde considerar um determinado incremento e passar a considerar um determi-nado número de incrementos. Assim, temos:

(defun enumera-n (a b n)(parametrica-n identidade a b n))

Uma vez que a função pontos-função opera precisamente da mesmamaneira que a função parametrica, também ela sofre do mesmo problemade acumulação de erros de arrendondamento. Para o contornarmos, podemosusar a mesma abordagem:

(defun pontos-funcao-n (pfn:f pfn:x0 pfn:x1 pfn:n)(parametrica-n

(lambda (x)(xy x (pfn:f x)))

pfn:x0pfn:x1pfn:n))

10Como deverá ser óbvio, a função enumera (definida na secção ??) sempre sofreu deste prob-lema pois os cálculos que realizava na sua prévia definição recursiva são exactamente os mes-mos que agora realiza na sua actual definição em termos de parametrica.

41

As funções parametrica-n e pontos-funcao-n permitem-nos gerarcurvas com grande simplicidade. São, consequentemente, um excelente pontode partida para a experimentação. Nesta secção vamos visualizar algumas dascurvas que, por uma razão ou outra, ficaram para a história da Matemática.

2.8 Espiral de Fermat

A espiral de Fermat é uma curva semelhante a uma espiral de Arquimedesmas em que a equação que a define é

ρ2 = α2θ

Resolvendo em ordem a ρ, obtemos

ρ = ±α√θ

Dividindo a curva em duas metades para lidar com os dois sinais, temos:

(defun meia-espiral-fermat (p a t1 n)(parametrica-n

(lambda (ti)(+pol p

(* a (sqrt ti))ti))

0t1n))

(defun grafico-espiral-fermat (p a t1 n)(spline-pontos (meia-espiral-fermat p (+ a) t1 n))(spline-pontos (meia-espiral-fermat p (- a) t1 n)))

Para vermos um exemplo da espiral de Fermat, podemos avaliar a seguinteexpressão:

(grafico-espiral-fermat (xy 0 0) 1.0 (* 16 pi) 400)

O resultado da avaliação anterior está representado na Figura 16.Um aspecto interessante da espiral de Fermat é o facto de ela modelar al-

guns fenómenos naturais, em particular, o arranjo das sementes numa flor degirassol. Num girassol, as sementes são dispostas numa superfície circular e,de modo a conseguir fazer crescer o maior número de sementes que for pos-sível, elas encontram-se encostadas umas às outras, da forma mais compactaque for possível.

Nestas flores, cada semente está posicionada de acordo com as equações11ρ = α

√n

θ = δ × n

11Este modelo foi proposto por H. Vogel em 1979 [].

42

Figura 16: A espiral de Fermat para θ ∈ [0, 16π].

em que n é o índice da semente contado a partir do centro da flor12, α é ofactor de escala e δ é o ângulo dourado (também chamado ângulo de Fibonacci)e definido por δ = π

Φ2 onde Φ =√

5+12 é a razão dourada. Da definição resulta

que δ = 2.39996 ≈ 2.4.Como podemos ver, esta equação é idêntica à da espiral de Fermat mas

com a diferença de o ângulo θ não crescer em função de n mas sim em funçãode δ × n, afastando cada duas sementes de um ângulo δ.

Para visualizarmos esta curva, é preferível desenhar uma “semente” emcada coordenada. Assim, ao invés de unirmos os pontos com linhas ou splines,como fazem as funções pline-pontos e spline-pontos, vamos criar umanova função de ordem superior chamada grafico-pontos e que recebe,para além da lista de pontos, a função a aplicar a cada ponto, função essaque terá a responsabilidade de fazer um desenho apropriado.

(defun grafico-pontos (gp:pts gp:f)(foreach gp:p gp:pts

(gp:f gp:p)))

Podemos agora definir a função girassol que, dado um ponto centralp, um factor de crescimento a, um ângulo d, um raio r e um número de se-mentes n, desenha as sementes do Girassol com um círculo de raio r para cadasemente.

(defun girassol (p a d r n)(grafico-pontos

(parametrica-n(lambda (ti)(+pol p

(* a (sqrt ti))

12Este índice é inversamente proporcional à ordem de crescimento da semente.

43

Figura 17: A disposição das sementes de um Girassol.

Figura 18: A disposição das sementes de Girassóis imaginários em que, daesquerda para a direita, o ângulo delta corresponde a um incremento, relati-vamente ao ângulo dourado π

Φ2 de +0.03, +0.02, +0.01, +0.00, −0.01, −0.02 e−0.03.

(* d ti)))1nn)

(lambda (p)(circulo p r))))

As seguintes avaliações permitem-nos desenhar uma aproximação à dis-posição das sementes do Girassol:

(setq angulo-dourado (/ 2*pi (quadrado (/ (1+ (sqrt 5)) 2))))

(girassol (xy 0 0) 1.0 angulo-dourado 0.75 200)

O resultado está visível na Figura 17.É interessante verificar que a disposição das sementes é extremamente sen-

sível ao ângulo δ. Na Figura 18 estão desenhados girassóis em tudo idênticosao da Figura 17 excepto no ângulo δ que difere do ângulo dourado π

Φ2 emapenas umas centésimas de radiano.

2.9 Cissóide de Diocles

Diz a lenda que, no século V antes de Cristo a população Grega foi atingidapela peste. Na esperança de uma resposta, os Gregos recorreram ao Oráculode Delos que profetizou que o problema estava na incorrecta veneração que

44

estava a ser prestada ao Deus Apolo. De acordo com o Oráculo, Apolo sóficaria apaziguado se se duplicasse o volume do altar em forma de cubo queos Gregos lhe tinham dedicado.

Os Gregos, na tentativa de rapidamente se livrarem dos terríficos efeitos dapeste, encetaram de imediato a tarefa de construção de um novo altar cúbicomas, infelizmente, ao invés de duplicarem o seu volume, duplicaram a suaaresta, implicando que o volume final era oito vezes maior que o volume origi-nal e não apenas duas vezes maior como o oráculo tinha ordenado. Aparente-mente, o oráculo sabia o que dizia pois Apolo não se satisfez com o novo altare a peste continuou a devastar a Grécia.

Após terem percebido o erro, os Gregos tentaram então descobrir qual aalteração correcta a fazer ao comprimento da aresta do cubo para duplicar oseu volume mas nunca conseguiram encontrar uma solução. A duplicaçãodo volume de um cubo passou então a designar-se o problema de Delos e,durante séculos, atormentou os geómetras.13 Foi apenas dois mil anos maistarde, pela mão de Descartes, que se demonstrou que as técnicas Gregas—que limitavam a construção geométrica ao uso de régua e compasso—nuncapoderiam resolver o problema.

No entanto, muito antes de Descartes, no século II antes de Cristo, o matemáticoGrego Diócles tinha encontrado uma “solução” mas à custa da utilização deuma curva especial, actualmente denominada cissóide de Diócles. Essa curvaextraordinária, infelizmente, não é desenhável apenas empregando régua ecompasso, o que implica que a solução encontrada seria, quanto muito, umasolução aproximada e não a verdadeira solução do problema.

A cissóide de Diócles define-se pela equação

y2(2a− x) = x3, x ∈ [0, a[

Colocando y em termos de x, obtemos:

y = ±√

x3

2a− x

Infelizmente, esta formulação da curva é pouco apropriada pois obriga-nosa tratar separadamente os sinais±. Uma conversão para coordenadas polares,permite-nos obter

ρ2 sin2 θ(2a− ρ cos θ) = ρ3 cos3 θ

Simplificando e usando a identidade Pitagórica sin2 θ + cos2 θ = 1, obtemos

(1− cos2 θ)(2a− ρ cos θ) = ρ cos3 θ

ou seja,2a(1− cos2 θ)− ρ cos θ + ρ cos3 θ = ρ cos3 θ

Simplificando, obtemos finalmente

ρ = 2a(1

cos θ− cos θ)

13Felizmente, a peste não durou tanto como as dificuldades dos geómetras.

45

Uma vez que cos±π2 = 0, a curva tende para infinito para aqueles valores. Isto

delimita o intervalo de variação a θ ∈]− π2 ,+

π2 [.

Obviamente, para transformarmos a representação polar numa represen-tação paramétrica fazemos simplesmente ρ(t) = 2a(

1cos t

− cos t)

θ(t) = t

Finalmente, para permitir “centrar” a curva num ponto arbitrário, vamosproceder a uma translação a partir desse ponto. Assim, para definirmos estacurva em Auto Lisp basta-nos então fazer:

(defun cissoide-diocles (p a t0 t1 n)(parametrica-n

(lambda (ti)(+pol p

(* 2 a (- (/ 1.0 (cos ti)) (cos ti)))ti))

t0t1n))

A Figura 19 mostra uma sequência de Cissóides de Diócles desenhadaspela expressões:

(spline-pontos (cissoide-diocles (xy 0 0) 10.0 -0.65 0.65 100))(spline-pontos (cissoide-diocles (xy 5 0) 5.0 -0.8 0.8 100))(spline-pontos (cissoide-diocles (xy 10 0) 2.5 -1.0 1.0 100))(spline-pontos (cissoide-diocles (xy 15 0) 1.0 -1.25 1.25 100))(spline-pontos (cissoide-diocles (xy 20 0) 0.5 -1.4 1.4 100))

2.10 Lemniscata de Bernoulli

Em 1694, Bernoulli publicou uma curva a que deu o nome de lemniscata. Essacurva acabou por se tornar imensamente famosa por ter sido adoptada comosímbolo para a representação do infinito: ∞. Actualmente, a curva é con-hecida por lemniscata de Bernoulli, para a distinguir de outras curvas quepossuem uma forma semelhante.

A lemniscata de Bernoulli é descrita pela equação

(x2 + y2)2 = a2(x2 − y2)

Infelizmente, como já discutimos anteriormente, esta forma de represen-tação analítica da curva é pouco apropriada para o seu desenho pois é difícilcolocar uma das variáveis em termos da outra. No entanto, se lhe aplicarmosa conversão de coordenadas polares para rectangulares obtemos

(ρ2 cos2 θ + ρ2 sin2 θ)2 = a2(ρ2 cos2 θ − ρ2 sin2 θ)

46

Figura 19: Cissóides de Diocles. Da esquerda para a direita, os parâmetros sãoa = 10, t ∈ [−0.65, 0.65], a = 5, t ∈ [−0.8, 0.8], a = 2.5, t ∈ [−1, 1], a = 1, t ∈[−1.251.25] e a = 0.5, t ∈ [−1.4, 1.4].

Dividindo ambos os termos por ρ2 e aplicando as identidades trigonométricassin2 x+ cos2 x = 1 e cos2 x− sin2 x = cos 2x, obtemos

ρ2 = a2 cos 2θ

Esta equação é agora trivial de se converter para a forma paramétrica:ρ(t) = ±a

√cos 2t

θ(t) = t

Note-se que a presença do símbolo ± indica que, na verdade, se estão atraçar duas curvas em simultâneo. Para simplificar, vamos traçar cada umadestas curvas independentemente. Assim, vamos começar por definir umafunção de calcula meia lemniscata com origem no ponto p:

(defun meia-lemniscata-bernoulli (p a t0 t1 n)(parametrica-n

(lambda (ti)(+pol p

(* a (sqrt (cos (* 2 ti))))ti))

t0t1n))

Em seguida, definimos uma função que desenha a lemniscata completa apartir do desenho de duas meias lemniscatas:

(defun grafico-lemniscata-bernoulli (p a t0 t1 n)(spline-pontos (meia-lemniscata-bernoulli p (+ a) t0 t1 n))(spline-pontos (meia-lemniscata-bernoulli p (- a) t0 t1 n)))

47

Figura 20: Lemniscata de Bernoulli.

Podemos agora visualizar a “infinidade” produzida por esta curva atravésda seguinte expressão:

(grafico-lemniscata-bernoulli (xy 0 0) 1.0 -pi/4 pi/4 200)

O resultado está representado na Figura 20.

Exercício 2.10.1 Embora nos exemplos anteriores tenhamos empregue a representação paramétricapor esta ser a mais simples, nem sempre isso acontece. Por exemplo, a lemniscata de Gerono, es-tudada pelo matemático Camille-Christophe Gerono, define-se matematicamente pela equação

x4 − x2 + y2 = 0

Resolvendo em ordem a y, obtemos

y = ±px2 − x4

Para permanecer no plano real, é necessário que x2 − x4 ≥ 0, o que implica x ∈ [−1, 1].Para evitar ter de desenhar duas curvas (provocadas pela presença do símbolo±), podemos

ser tentados a usar a representação paramétrica desta curva, definida por8>><>>:x(t) =

t2 − 1

t2 + 1

y(t) =2t(t2 − 1)

(t2 + 1)2

Infelizmente, enquanto a representação funcional apenas precisa de fazer x variar entre −1 e+1, a representação paramétrica precisa de fazer t variar entre −∞ e +∞, o que nos levantauma impossibilidade computacional. Por este motivo, neste caso a representação funcional épreferível.

Tendo estas considerações em conta, defina a função grafico-lemniscata-gerono quedesenha a lemniscata de Gerono.

2.11 Curva de Lamé

A curva de Lamé é uma curva cujos pontos satisfazem a equação∣∣∣xa

∣∣∣n+∣∣∣yb

∣∣∣n= 1

em que n > 0 e a e b são os raios da curva.

48

Figura 21: A curva de Lamé para a = 2, b = 1, n = p/q, p, q ∈ 1..8. A variávelp varia ao longo do eixo das abcissas, enquanto q varia ao longo do eixo dasordenadas.

A curva foi estudada no século dezanove pelo matemático Francês GabrielLamé como uma generalização óbvia da elipse. Quando n é um número racional,a curva de Lamé diz-se uma superelipse. Quando n > 2, obtemos uma hipere-lipse, tanto mais próxima de um rectângulo quanto maior for n. Quando n < 2obtemos uma hipoelipse, tanto mais próxima de uma cruz quanto menor forn. Para n = 2, obtemos uma elipse e, para n = 1, obtemos um losângulo. Estasvariações são visiveis na Figura 21 que apresenta variações desta curva paraa = 2, b = 1 e diferentes valores de n.

A curva de Lamé tornou-se famosa quando foi proposta pelo cientista epoeta Dinamarquês Piet Hein como um compromisso estético e funcional en-tre formas baseadas em padrões rectangulares e formas baseadas em padrõescurvilineos. No seu estudo para uma intersecção de ruas no bairro SergelsTorg, em Estocolmo, em que se estava a hesitar entre uma rotunda tradicionalou um arranjo rectangular de vias, Piet Hein sugeriu a superelipse como formaintermédia entre aquelas duas, produzindo o resultado que está visível naFigura 22. De todas as superelipses, as mais esteticamente perfeitas eram, naopinião de Piet Hein, as parameterizadas por n = 5

2 e ab = 6

5 .Para desenharmos a curva de Lamé é preferível utilizar a seguinte formu-

lação paramétrica.

x (θ) = a cos2n θ · sgn cos θ

y (θ) = b sin2n θ · sgn sin θ

− π ≤ θ < π

A tradução desta fórmula para Lisp é directa:

(defun superelipse (p a b n ti)(+xy p

(* a (expt (expt (cos ti) 2) (/ 1.0 n)) (signum (cos ti)))(* b (expt (expt (sin ti) 2) (/ 1.0 n)) (signum (sin ti)))))

49

Figura 22: A superelipse proposta por Piet Hein para a praça Sergels, em Esto-colmo. Fotografia de Nozzman.

50

Para gerarmos uma sequência de pontos da superelipse podemos, comoanteriormente, empregar a função parametrica-n:

(defun pontos-superelipse (p a b n pts)(parametrica-n

(lambda (ti)(superelipse p a b n ti))

-pipipts))

Finalmente, para traçar a curva da superelipse, podemos definir:

(defun curva-superelipse (p a b n pts)(spline-pontos

(pontos-superelipse p a b n pts)))

As superelipses da Figura 21 foram geradas usando a função anterior. Paraisso, definimos uma função testa-superelipses que, para valores de a e be para uma sequência de números, testa todas as combinações de expoente n =p/q, com p e q a tomarem sucessivos valores dessa sequência. Para se podervisualizar as várias superelipses cada uma tem uma origem proporcional àcombinação p e q usada:

(defun testa-superelipses (a b ns)(foreach num ns

(foreach den ns(curva-superelipse(xy (* num (* 2.5 a)) (* den (* 2.5 b)))ab(/ (float num) (float den))100))))

A Figura 21 foi gerada directamente a partir da avaliação da seguinte ex-pressão:

(testa-superelipses 2.0 1.0 (list 1 2 3 4 5 6 7 8))

Exercício 2.11.1 Defina a função tanque-superelipse que constrói um tanque de formasuperelíptica idêntico ao da praça de Sergels Torg, tal como se apresenta em seguida:

51

Sugestão: defina previamente uma função denominada parede-curva que constrói pare-des ao longo de uma determinada curva. A função deverá recebe a espessura e altura daparede a construir e uma entidade representando a curva (por exemplo, um círculo, uma elípse,uma spline, etc). Considere também a utilização da função extrusao-caminho definida nasecção ??.

Exercício 2.11.2 Defina a função tanque-circular que constrói um tanque circular idênticoa cada um dos que estão contidos dentro da praça de Sergels Torg, tal como se apresenta deseguida:

52

Exercício 2.11.3 Defina a função tanques-circulares que constrói uma sucessão de tan-ques circulares cujos centros estão localizados ao longo de uma superelipse, tal como se apre-senta na imagem seguinte:

A função deverá receber os parâmetros da superelipse, os parâmetros de um tanque circu-lar e o número de tanques a criar.

Exercício 2.11.4 Defina uma função que, invocando as funções tanque-superelipse e tanques-circulares,cria uma praça tão semelhante quanto possível à praça de Sergels Torg, tal como se apresentana imagem seguinte:

53

Figura 23: A pala do Pavilhão de Portugal. Fotografia de Luis Mendes.

x

y

a

Figura 24: Perfil da pala de Siza Vieira.

2.12 Catenária

O Pavilhão de Portugal foi um projecto desenvolvido pelo arquitecto ÁlvaroSiza Vieira com a colaboração do arquitecto Eduardo Souto de Moura. O edifí-cio é constituído por dois pórticos separados por uma praça coberta—a PraçaCerimonial. A cobertura da praça é feita por uma imponente pala de betãopré-esforçado com um peso de 1400 toneladas. A visão de Siza Vieira era deque esta pala deveria ser um corpo sólido mas com a forma de uma lona es-tendida entre os dois pórticos, tal como se visualiza na Figura 23.

Vista transversalmente, esta “lona” de betão assemelha-se a um cabo pen-durado pelas suas extremidades, tal como se apresenta na Figura 24. Na ver-dade, a pala é constituída por vários cabos paralelos envolvidos por uma finalâmina de betão.

Para o correcto dimensionamento desta estrutura é importante conhecer-mos rigorosamente a sua geometria. Durante séculos, pensou-se que um cabosuspenso pelas suas extremidades e sujeito apenas ao seu peso próprio for-maria uma curva em forma de parábola. Galileu afirmou-o mas não o con-seguiu provar. Em 1669, Jungius provou teórica e experimentalmente que acurva em questão não é, de facto, uma parábola, mas, por falta de ferramentasmatemáticas, não conseguiu descobrir a verdadeira forma. Foi apenas coma invenção do cálculo infinitesimal, por Leibnitz e Newton, que se atingiua sofisticação matemática necessária, tendo o problema sido finalmente re-solvido, em 1690, por Johann Bernoulli. Ficou então demonstrado que a forma

54

da curva em questão é descrita pela função14

y = a coshx

a

A curva definida por esta função denomina-se catenária.15 Na definiçãoanterior, a função cosh é o cosseno hiperbólico, definido matematicamente por

coshx =ex + e−x

2

e cuja tradução para Auto Lisp é:

(defun catenaria (a x)(* a (cosh (/ x a))))

A função cosseno hiperbólico não se encontra definida em Auto Lisp masé trivial fazê-lo:

(defun cosh (x)(/ (+ (exp x) (exp (- x)))

2))

Exercício 2.12.1 Defina as funções seno hiperbólico (sinh) e tangente hiperbólica (tanh) a par-tir das definições matemáticas:

sinhx =ex − e−x

2

tanhx =ex − e−x

ex + e−x

Exercício 2.12.2 Defina as funções hiperbólicas inversas arco-seno hiperbólico (asinh), arco-cosseno hiperbólico (acosh) e arco-tangente hiperbólico (atanh) cujas definições matemáticassão:

asinhx = sinh−1 x = ln(x+px2 + 1)

acoshx = cosh−1 x = ± ln(x+px2 − 1)

atanhx = tanh−1 x =

(12

ln( 1+x1−x

), se |x| < 112

ln( x+1x−1

), se |x| > 1

Para computarmos os pontos da curva catenária vamos considerar que estase desenvolve no plano Y = 0, sendo a coordenada x a variável independentee a coordenada z a variável dependente. Dado um ponto p de posicionamentoda curva no espaço, dado o coeficiente a da função catenária z = a cosh x

a ,dados os limites do intervalo [x0, x1] e, finalmente, dado o número de pontosa computar, a seguinte função pontos-catenaria parameteriza a funçãoparametrica-n de modo a que esta gere n coordenadas p+(x, 0, z) da curvacatenária:

14É importante referir que esta função descreve um modelo teórico que é apenas uma aprox-imação do que ocorre na realidade. Entre outras suposições, este modelo assume que o caboé perfeitamente flexível e totalmente inelástico e que não existem quaisquer outros esforços aconsiderar para além do peso do cabo (como sejam ventos ou sismos).

15A palavra catenária deriva da palavra latina catena—que significa corrente—pela forma queassume uma corrente metálica quando pendurada pelas suas extremidades.

55

Figura 25: Catenárias em AutoCad.

(defun pontos-catenaria (p a x0 x1 n)(parametrica-n(lambda (x)

(+xyz p x 0 (* a (cosh (/ x a)))))x0 x1 n))

Podemos agora experimentar a criação da curva catenária e podemos usarestes pontos directamente no AutoCad como argumentos para a função pline-pontosou, melhor ainda, para a função spline-pontos. A Figura 25 foi gerada apartir da seguinte interacção:

(spline-pontos(pontos-catenaria (xyz 0 0 0) 2.0 -4.0 4.0 10))

(spline-pontos(pontos-catenaria (xyz 0 0 0) 4.0 -4.0 4.0 10))

(spline-pontos(pontos-catenaria (xyz 0 0 0) 8.0 -4.0 4.0 10))

Para criarmos a pala propriamente dita, precisamos de dar “espessura” e“largura” à curva. Para isso, podemos criar um rectângulo correspondente àsecção da pala (usando, por exemplo, a função regiao-rectangular definidana página ??), alinhamo-lo com um plano que inclua o eixo z e aplicamos umaextrusão deste rectângulo ao longo da curva catenária:

(extrusao-caminho(regiao-rectangular (xyz 100 0 0) 0 60 1)(spline-pontos(pontos-catenaria (xyz 100 0 0) 30 -30 30 10)))

O resultado está representado na Figura 26.

56

Figura 26: Uma pala obtida pelo deslocamento de um rectângulo ao longo deuma curva catenária. Esta curva está ainda visível no interior da pala.

Exercício 2.12.3 Escreva uma expressão que, empregando geração de números aleatórios, con-strói uma imensidão de palas com diferentes parâmetros, tal como se apresenta na seguinteimagem:

2.13 Pontos Fixos

Para completarmos a modelação da pala do Pavilhão de Portugal falta-nosagora determinar o coeficiente a e os limites x0 e x1 apropriados para a curvacatenária pretendida. No entanto, para nos aproximarmos mais dos requisitosarquitecturais do desenho original de Siza Vieira, é conveniente adaptarmos afunção que define a curva catenária, adicionando-lhe um deslocamento verti-cal z0 e determinando o parâmetro a em função de parâmetros mais “arquitec-turais,” como o comprimento d da praça a cobrir, a altura mínima da pala (h0)e a altura dos engastes da pala (h1), tal como se apresenta na Figura 27.

Com o deslocamento vertical obtido pela soma do termo z0, a fórmula dacatenária fica:

z = z0 + a coshx

a

No ponto mais baixo da catenária, x = 0, temos z = h0, o que implica

h0 = z0 + a cosh 0

57

x

z

d2

h1 − h0

h0

Figura 27: A catenária deslocada na vertical.

Daqui resultaz0 = h0 − a

Por outro lado, no ponto mais alto, x = d/2, temos z = h1, o que implica

h1 = z0 + a coshd/2a

Daqui resulta

h1 = h0 + a(coshd

2a− 1)

Seria agora desejável poder determinar a em função de d, h1 e h0, mas, infeliz-mente, a equação é não-linear e não existe nenhuma fórmula simplificada parao fazermos. De facto, por mais que tentemos “resolver” a variável a, obtemosapenas duas alternativas:16

a =h1 − h0

cosh d2a − 1

∨ a =d

2 arccosh(h1−h0a + 1)

Não sendo possível a obtenção de uma fórmula para calcular a em funçãodos outros parâmetros podemos, ao menos, tentar obter uma aproximação dea para valores determinados de d, h1 e h0. Para isso há vários métodos numéri-cos que podemos empregar, como sejam o método da bissecção ou o métodode Newton. Outra solução, ainda mais simples, será aproveitar o facto de asequações anteriores estarem escritas na forma a = f(a), o que implica queo valor de a que satisfaz as equações tem de ser um ponto fixo da respectivafunção f , i.e., a aplicação da função ao valor do ponto fixo produz exactamenteo mesmo valor.

Nem todas as funções possuem pontos fixos e, quando os possuem, nemsempre temos uma forma fácil de os encontrar. No entanto, há um caso par-ticular de ponto fixo que é particularmente fácil de encontrar: o ponto fixoatractivo. Se a for um ponto fixo atractivo então, partindo de qualquer pontoa0 suficientemente próximo de a e aplicando sucessivamente a função f

a0, f(a0), f(f(a0)), f(f(f(a0))), f(f(f(f(a0)))), . . .

atinge-se sempre o ponto a, i.e., a sucessão an+1 = f(an) converge para o pontofixo a = f(a) a partir de qualquer aproximação a0 suficientemente próxima dea.

16Na segunda alternativa, arccosh é o arco cosseno hiperbólico, função inversa da funçãocosseno hiperbólico e que se define por arccosh(x) = cosh−1(x) = ± ln(x+

√x2 − 1).

58

A título de exemplo, considere-se a função cosseno. Se calcularmos su-cessivas aplicações desta função a partir de um valor inicial qualquer, iremosconstatar que convergimos sempre para o valor 0.739085, tal como se pode verusando a REPL do Auto Lisp.17

_$ (cos 2)-0.416147_$ (cos (cos 2))0.914653_$ (cos (cos (cos 2)))0.610065_$ (cos (cos (cos (cos 2))))0.819611_$ (cos (cos (cos (cos (cos 2)))))0.682506_$ (cos (cos (cos (cos (cos (cos 2))))))0.775995_$ (cos (cos (cos (cos (cos (cos (cos 2)))))))0.713725_$ (cos (cos (cos (cos (cos (cos (cos (cos 2))))))))0.755929_$ (cos (cos (cos (cos (cos (cos (cos (cos (cos 2)))))))))0.727635

Obviamente, calcular pontos fixos de forma manual é demasiado entedi-ante. Convém por isso fazermos uma função iteradora que o execute de modoautomático. Para isso, a função iteradora deverá receber a função f a iterar ea aproximação inicial a0 a considerar. Internamente, a função iteradora iráaplicar a função iterada f à aproximação inicial a0, produzindo uma novaaproximação, a1. Se a1 = a0, então encontrámos um ponto fixo. Se não, oproblema reduz-se a encontrar o ponto fixo de f mas partindo da aproximaçãoa1.

A definição desta função é a seguinte:18

(defun ponto-fixo (pf:f pf:x0 / pf:x1)(setq pf:x1 (pf:f pf:x0))(if (= pf:x1 pf:x0)

pf:x1(ponto-fixo pf:f pf:x1)))

Note-se que a função ponto-fixo recebe uma função como argumento, oque implica que ponto-fixo é uma função de ordem superior. Usando estafunção, é agora trivial calcular pontos fixos:

17O mesmo efeito se obtém com uma vulgar calculadora, começando por inserir um númeroqualquer e, seguidamente, premindo consecutivamente a tecla do cosseno. O valor nomostrador irá convergir e, a dada altura, permanecerá constante.

18Esta função possui uma incorrecção: não tem em conta os erros de arredondamento quesão inevitáveis no cálculo com números reais. Este facto pode fazer o operador de igualdade =devolver falso, mesmo quando os dois argumentos são números suficientemente próximos. Naverdade, em métodos numéricos de aproximação, nunca se comparam directamente quaisquernúmeros reais a e b, testa-se apenas se o erro absoluto ε = |a − b| ou o erro relativo η = |a−b|

inferior a um valor de tolerância pré-estabelecido e suficientemente pequeno.Auto Lisp providencia a função equal para esse fim. Esta função recebe (entre outras possi-

bilidades) dois números que irá comparar. Se for também passado um terceiro argumento, estedeverá ser uma tolerância que será usada como limite do erro absoluto.

59

_$ (ponto-fixo cos 2)0.739085

Infelizmente, nem todas as funções se portam bem no que diz respeito aencontrar pontos fixos. Por exemplo, a função quadrado tem um ponto fixoóbvio para x = 1 mas este não é atractivo pois x2 < x para x ∈]0, 1[ e x2 > xpara x ∈]1,+∞[, i.e., para valores inferiores ao ponto fixo x = 1, a aplicaçãoda função quadrado produz valores ainda mais inferiores e, para valores su-periores, produz valores ainda mais superiores. Assim, a menos que a aprox-imação inicial ao ponto fixo seja precisamente o valor x = 1, ou o processoconverge para o outro ponto fixo x = 0 ou diverge para infinito. Esse compor-tamento é visível nas seguintes tentativas:

_$ (ponto-fixo (lambda (x) (* x x)) 1.0)1.0_$ (ponto-fixo (lambda (x) (* x x)) 0.9)0.0_$ (ponto-fixo (lambda (x) (* x x)) 1.1)1.#INF

Uma propriedade interessante dos pontos fixos é que, se a é um pontofixo de f então, por definição, a = f(a) e, consequentemente, também temosa = f−1(a), i.e., tanto podemos usar a função f como a sua inversa f−1 paraencontrar pontos fixos. Esta propriedade dá-nos uma segunda hipótese paraencontrar um ponto fixo: se a sucessiva invocação de f não converge, entãopodemos tentar usar a função inversa f−1.

Por exemplo, vimos que no caso da função quadrado f(x) = x2, emboraela tenha o ponto fixo óbvio x = 1, a sua sucessiva invocação não convergepara ele. No entanto, já o contrário acontece com a função inversa f(x) =

√x:

_$ (ponto-fixo sqrt 2.0)1.0_$ (ponto-fixo sqrt 1.1)1.0_$ (ponto-fixo sqrt 0.9)1.0_$ (ponto-fixo sqrt 0.1)1.0

Para a curva catenária, as equações deduzidas para o pârametro a que de-fine a forma da catenária são:

a =h1 − h0

cosh( d2a)− 1∨ a =

d

2 arccosh(h1−h0a + 1)

No caso da pala idealizada por Siza Vieira para o Pavilhão de Portugal,o seu comprimento horizontal d é de 67.5 metros, sendo a sua altura h0 noponto central de 10 metros, enquanto que a altura h1 nas extremidades da palaé de 13 metros. Isto implica que para determinarmos a temos de encontrar umponto fixo da função

f(a) =3

cosh(33.75a )− 1

60

ou, alternativamente, da função inversa

f(a) =33.75

arccosh( 3a + 1)

Ao experimentarmos com a primeira função, obtemos:

_$ (ponto-fixo (lambda (a) (/ 3.0 (- (cosh (/ 33.75 a)) 1))) 1.0); error: divide by zero_$ (ponto-fixo (lambda (a) (/ 3.0 (- (cosh (/ 33.75 a)) 1))) 10.0); error: divide by zero_$ (ponto-fixo (lambda (a) (/ 3.0 (- (cosh (/ 33.75 a)) 1))) 100.0); error: divide by zero

Este comportamento indica que, independentemente do valor da aprox-imação inicial, obtemos sempre um erro de divisão por zero. Isso aconteceporque à medida que vamos iterando as invocações da função, a aproximaçãoinicial vai tendendo para zero, até que se torna tão pequena que, por falta deprecisão, fica igual a zero. Nesse momento, a divisão de 33.75 pela aproxi-mação produz um erro aritmético.

Resta-nos experimentar com a função inversa:

(defun acosh (x)(log (+ x (sqrt (- (* x x) 1)))))

_$ (ponto-fixo (lambda (a) (/ 33.75 (acosh (+ (/ 3 a) 1)))) 1.0)190.342

Temos finalmente o valor do parâmetro a que nos permite desenhar comexactidão a catenária idealizada por Siza Vieira. A curva pretendida é assimdefinida por

z = 10 + 190.342(coshx

190.342− 1)

e é válida no intervalo x ∈ [−33.75, 33.75].Naturalmente, a partir do momento em que temos as ferramentas funda-

mentais para calcular e desenhar catenárias, podemos combiná-las numa sóferramenta que, a partir dos vários parâmetros arquitecturais desejados, criaa catenária em questão. Para concretizar, vamos considerar como parâmetrospara o desenho de uma pala:

p Ponto de posicionamento da catenária,h0 Altura da curva no ponto central, a meia distância das extremidadesh1 Altura da curva nas extremidadesd Comprimento horizontal da curva (ao longo da linha longitudinal)n Número de pontos a considerar para a curva catenária

O primeiro passo do cálculo da pala é determinar o parâmetro a da curvacatenária usando a função de ordem superior ponto-fixo para determinar oponto fixo da função

f(a) =d

2 arccosh(h1−h0a + 1)

61

Aqui, temos de tomar em atenção que o sinal da diferença entre h0 e h1 indicaa orientação da curva. Se h0 < h1, temos uma pala e o coeficiente a é positivo.Se h0 > h1 temos um arco e o coeficiente a é negativo.19 Em seguida, criamosuma lista de coordenadas da função catenária z = h0 + a(cosh x

a − 1) usando afunção de ordem superior pontos-funcao e, finalmente, criamos uma splineque passe por esses pontos usando a função spline-pontos.

Eis o programa:

(defun curva-catenaria (p h0 h1 d n / s a)(setq s (abs (- h1 h0)))(setq a (* (signum (- h1 h0))

(ponto-fixo(lambda (a)(/ d 2.0 (acosh (+ (/ s a) 1))))

1.0)))(spline-pontos

(parametrica-n(lambda (x)(+xyz p x 0 (+ h0 (* a (- (cosh (/ x a)) 1)))))

(/ d -2.0)(/ d +2.0)n)))

Podemos experimentar a função desenhando várias catenárias em simultâ-neo, fazendo variar apenas a altura do ponto central:

(foreach h0 (list -20 -15 -10 -5 -1 1 5 10 15 20)(curva-catenaria (xy 0 0) h0 0 80 100))

O resultado está representado na Figura 28.Como referimos, no caso da pala de Siza Vieira, temos h0 = 10, h1 = 13 e

d = 67.5. Para recriarmos a pala em três dimensões, basta-nos usar o AutoCadpara fazer deslocar um rectângulo com 58 metros de comprimento e 0.2 metrosde altura (representando uma secção transversal da pala) ao longo da curvacatenária:

(extrusao-caminho(regiao-rectangular (xyz 0 0 0) 0 58 0.2)(curva-catenaria (xyz 0 0 0) 10 13 67.5 20))

O resultado está visível na Figura 29.

2.13.1 O Arco de St. Louis

A cidade de St. Louis, fundada em 1764 na confluência dos rios Mississipi eMissouri, foi, durante muitos anos, o último ponto de paragem para os pio-neiros que se lançaram à conquista do Oeste Americano. A cidade ficou entãoa ser conhecida como o “portão do Oeste.”

Para celebrar a conquista pioneira do oeste americano, em 1947, foi lançadoum concurso para o desenho de um monumento comemorativo. O concurso

19O sinal do coeficiente pode ser facilmente determinado usando a função signum que foiintroduzida na secção ??.

62

Figura 28: Várias catenárias sobrepostas, com parâmetros h0 ∈−20,−15,−10,−5,−1, 1, 5, 10, 15, 20, h1 = 0, d = 80, n = 100.

Figura 29: A pala do Pavilhão de Portugal (em perspectiva).

63

Figura 30: O arco de St. Louis. Fotografia de Kelly Kirkpatrick.

foi ganho pelo arquitecto Eero Saarinen que, com a ajuda do engenheiro HannskarlBandel, desenhou um arco de catenária invertida20 cuja secção é um triânguloequilátero. As paredes do arco são compostas por uma lâmina de aço inox-idável envolvendo uma estrutura de betão reforçado. Este arco é actualmenteo mais alto monumento nacional dos Estados Unidos. A Figura 30 mostra umaimagem do arco.

O arco tem precisamente 630 pés de distância entre as extremidades exte-riores dos apoios e os mesmos 630 pés de altura. A secção do arco varia deespessura, desde 54 pés na base até 17 pés no topo. O arco é oco e possui es-cadarias e um sistema de elevadores que leva os visitantes até uma plataformade observação no topo do arco.

Com base nestas informações, podemos deduzir que os parâmetros dacatenária exterior ao monumento são h0 = 630, h1 = 0 e d = 630. Para ger-armos esta catenária podemos então avaliar a expressão:21

(curva-catenaria (xy 0 0) 630 0 630 100)

Para gerar o arco a três dimensões vamos tirar partido das capacidades docomando loft do AutoCad, tal como o implementámos na função interpolacao-seccoes-caminhodefinida na secção ??. Para isso, vamos construir três triângulos equiláterosque definirão os limites da forma a criar. Dois desses triângulos equiláteros,cada um com 54 metros de lado, estarão colocados nas bases do arco. O ter-ceiro triângulo, com 17 metros de lado estará colocado no topo do arco. Os

20O arco, na realidade, não é uma catenária invertida pura mas sim uma catenária ligeira-mente alongada no topo.

21Para sermos fiéis às dimensões convém informarmos o AutoCad que pretendemos trabal-har com o sistema imperial.

64

Figura 31: Esquema da modelação do arco. À esquerda, apenas as secçõestriangulares e a curva usada para a interpolação. À direita, o arco produzidopor interpolação daquelas secções, usando a curva como caminho.

triângulos terão o seu centróide coincidente com a curva catenária que seráusada como caminho para a interpolação. A Figura ?? mostra a abordagemdescrita.

Exercício 2.13.1 Defina a função triangulo-xy que, a partir das coordenadas do centróidede um triângulo, do comprimento do lado desse triângulo e, finalmente, do ângulo de rotaçãodo triângulo, cria a região correspondente a esse triângulo assente no plano XY .

Exercício 2.13.2 Defina a função triangulo-yz que, à semelhança da função triangulo-xy,cria uma região triangular, mas agora assente no plano Y Z.

Para criarmos o arco de St. Louis podemos avaliar a expressão

(interpolacao-seccoes-caminho(list (triangulo-xy (xy (/ 630 -2.0) 0) 54 0)

(triangulo-yz (xyz 0 0 630) 17 pi)(triangulo-xy (xy (/ 630 +2.0) 0) 54 pi))

(curva-catenaria (xy 0 0) 630 0 630 100))

cujo resultado se encontra na Figura 32.

65

Figura 32: O arco de St. Louis gerado em AutoCad.

66

2.14 Funções de Ordem Superior sobre Listas

Uma vez que as listas constituem um aglomerado de elementos e, frequente-mente, precisamos de aplicar operações a cada um dos elementos de um aglom-erado, as listas são um tipo de dados natural para a definição de operações deordem superior.

2.14.1 Mapeamento

Uma das operações mais úteis é aquela que transforma uma lista noutra listaatravés da aplicação de uma função a cada elemento da primeira lista. Porexemplo, dada uma lista de números, podemos estar interessados em pro-duzir uma outra lista com os quadrados desses números. Neste caso, dizemosque estamos a mapear a função quadrado numa lista para produzir a lista dosquadrados. A definição da função apresenta o já típico padrão de recursão emlistas:

(defun mapeia-quadrado (lista)(if (null lista)

()(cons (quadrado (car lista))

(mapeia-quadrado (cdr lista)))))

Obviamente, estar a definir uma função apenas para mapear o quadradoé particularizar em excesso. Seria muito mais proveitoso definir uma funçãode ordem superior que mapeie qualquer função sobre uma lista. Felizmente, étrivial modificar a função anterior:

(defun mapeia (m:f m:lista)(if (null m:lista)

()(cons (m:f (car m:lista))

(mapeia m:f (cdr m:lista)))))

Com esta função é trivial produzir, por exemplo, o quadrado de todos osnúmeros de 10 a 20:

_$ (mapeia quadrado (enumera 10 20 1))(100 121 144 169 196 225 256 289 324 361 400)

2.14.2 Filtragem

Uma outra função muito útil é a que filtra uma lista. A filtragem é feita fornecendoum predicado que é aplicado a cada elemento da lista. Os elementos que sat-isfazem o predicado (i.e., em relação aos quais o predicado é verdade) sãocolecionados numa nova lista.

A definição é simples:

(defun filtra (f:p f:lista)(cond ((null f:lista)

())((f:p (car f:lista))

67

(cons (car f:lista)(filtra f:p (cdr f:lista))))

(t(filtra f:p (cdr f:lista)))))

Usando esta função podemos, por exemplo, obter apenas os quadradosdivisíveis por 3 dos números entre 10 e 20:

_$ (filtra (lambda (n) (= (rem n 3) 0))(mapeia quadrado (enumera 10 20 1)))

(144 225 324)

2.14.3 Redução

Uma terceira função de grande utilidade é a que realiza uma redução numalista. Esta função de ordem superior recebe uma operação e uma lista e vaireduzindo a lista através da “intercalação” da operação entre todos os ele-mentos da lista. Por exemplo, para somar todos os elementos de uma listal=(e0 e1 ...en) podemos fazer (reduz + l) e obter e0+e1+. . . +en. As-sim, temos:

_$ (reduz + (enumera 1 100 1))5050

A definição da função é bastante simples:

(defun reduz (r:f r:lista)(if (null (cdr r:lista))

(car r:lista)(r:f (car r:lista)

(reduz r:f (cdr r:lista)))))

A determinação do maior valor existente numa lista de números é outro ex-emplo de uma redução. Neste caso, a função que empregamos para combinarsucessivamente os valores da lista é a função max que devolve o maior entredois números. Se for l for a lista de números,(e0 e1 ... en−1 en), o maiordesses números pode-se obter através de (max e0 (max e1 ... (max en en)))que, obviamente, corresponde ao desenrolar da redução (reduz max l).

Através do uso de funções de ordem superior e, em particular, dos mapea-mentos, filtragens e reduções, é possível implementar facilmente algoritmosrazoavelmente sofisticados.

2.14.4 Bestialidades

Os praticantes da numerologia, i.e., do estudo das relações esotéricas entre osnúmeros e outras entidades, afirmam que o número da besta—666—se esconde

68

em várias expressões matemáticas cujo cálculo envolve colecções de números.22

Por exemplo, diz-se que ele surge na soma dos primeiros 36 números naturais,na soma dos quadrados dos primeiros 7 números primos ou ainda na somado número primo cujo índice é 3 × 3 × 3 com o número primo cujo índice é onúmero primo cujo índice é 3× 3× 3.

Para provarmos a primeira “bestialidade” basta-nos compor uma reduçãocom uma enumeração:

_$ (reduz + (enumera 1 36 1))666

Para provarmos a segunda e a terceira “bestialidades” temos primeiro deconseguir gerar uma lista de números primos. Como sabemos, um númeroprimo é um número maior que um que tem apenas dois divisores: o próprionúmero e a unidade.

Existem vários algoritmos que produzem listas de números primos. Umdos mais famosos é o crivo de Eratóstenes.23 O crivo de Eratóstenes parte deuma lista com os números inteiros desde 2 até ao maior número que se pre-tende. O algoritmo começa por separar o primeiro número dos restantes dalista e, em seguida, remove desta todos os números que forem divisíveis peloque foi separado pois, obviamente, não serão números primos. Este processoé repetido até não existirem mais números na lista.

Para exemplificar, consideremos uma lista com todos os inteiros desde 2 até20. De acordo com o crivo de Eratóstenes, esta lista é processada nos seguintespassos:24

1. 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20

2. 2 3,4/,5,6/,7,8/,9,10/ ,11,12/ ,13,14/ ,15,16/ ,17,18/ ,19,20/

3. 2,3 5,7,9/,11,13,15/ ,17,19

4. 2,3,5 7,11,13,17,19

5. 2,3,5,7 11,13,17,19

6. 2,3,5,7,11 13,17,1922O número da besta vem referido no Livro da Revelação (também conhecido por Livro do

Apocalipse), capítulo 13, versículo 18:

Aqui é que está a sabedoria: Quem tiver inteligência calcule o número dabesta, pois é numero de homem; e o seu número é seiscentos e sessenta e seis.

Estudos recentes parecem indicar que o número da besta, na realidade, é 616 pois é essenúmero que é indicado nos textos mais antigos que se encontram. O número 666 terá aparecidomais tarde como consequência de um erro de tradução mas, para os nossos propósitos, vamoscontinuar a usar o número 666.

23Eratóstenes foi director da biblioteca de Alexandria e trabalhou em inúmeras áreas, in-cluindo aritmética, geometria, história, geografia, astronomia, teatro, e poesia. Entre os seusfeitos mais famosos inclui-se a medição do diâmetro da Terra e da distância da Terra ao Sol.

24Como se pode ver pelo desenrolar do processo, a dada altura mais nenhum número é elim-inado. Não é difícil demonstrar que isso acontece quando o quadrado do número que está a serconsiderado é superior ao último dos números.

69

7. 2,3,5,7,11,13 17,19

8. 2,3,5,7,11,13,17 19

9. 2,3,5,7,11,13,17,19

Usando recursão é trivial reduzir o crivo da lista de números ao crivo dessalista sem o primeiro número e sem todos os que forem divisíveis por ele. Estaúltima parte é trivialmente implementável usando a função filtra. O casode paragem ocorre quando se pretende aplicar o crivo a uma lista vazia, casoem que o resultado é, naturalmente, a lista vazia. O uso da recursão permite-nos realizar facilmente as sucessivas filtragens necessárias:

(defun primos (numeros)(if (null numeros)

()(cons (car numeros)

(primos(filtra (lambda (e) (/= (rem e (car numeros)) 0))

(cdr numeros))))))

Usando esta função podemos agora facilmente calcular todos os númerosprimos até, digamos, 1000:

_$ (setq primos-ate-1000 (primos (enumera 2 1000 1)))(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 ...)

Podemos agora testar as duas últimas “bestialidades.” A penúltima dizque o número da besta se encontra na soma dos quadrados dos primeiros 7números primos.

_$ (reduz +(mapeia quadrado

(sublista primos-ate-1000 0 7)))666

A última “bestialidade” afirma que o número da besta ocorre na soma donúmero primo cujo índice é 3 × 3 × 3 com o número primo cujo índice é onúmero primo cujo índice é 3×3×3. Para provar esta bestialidade temos de noslembrar que a indexação em listas começa no número zero e não no númeroum, como é usual considerar em linguagem natural. Isto implica que temos desubtrair uma unidade ao índice para obter o elemento correcto. Assim, temos:

_$ (setq primo-3*3*3 (n-esimo (* 3 3 3) primos-ate-1000))103_$ (+ primo-3*3*3 (n-esimo primo-3*3*3 primos-ate-1000))666

Nas secções seguinte iremos mostrar operações de ordem superior sobrelistas em aplicações substancialmente mais úteis.

70

2.14.5 Funções de Ordem Superior com Múltiplas Listas

É frequentemente útil poder combinar duas listas numa só, realizando umadada operação com cada par de elementos de cada lista. Por exemplo, pode-mos querer somar os elementos das listas (1 2 3) e (4 5 6) para produzira lista (5 7 9). Para isso, podemos fazer uma variante da função mapeiaque, em vez de receber uma operação unária e uma só lista, recebe uma op-eração binária e duas listas e colecciona os resultados de aplicar a função aossucessivos elementos de cada uma das duas listas:

(defun mapeia2 (m:f m:lista0 m:lista1)(if (null m:lista0)

()(cons (m:f (car m:lista0) (car m:lista1))

(mapeia2 m:f (cdr m:lista0) (cdr m:lista1)))))

Usando esta função, podemos facilmente calcular uma lista com o produ-tos dos elementos de outras duas listas.

_$ (mapeia2 * (enumera 10 20 1) (enumera 10 20 1))(100 121 144 169 196 225 256 289 324 361 400)

Uma utilização potencialmente mais útil será a que, a partir de duas listasde números, produz uma lista de coordenadas bidimensionais. Por exemplo,consideremos a seguinte expressão:

_$ (mapeia2 xy (enumera 1 5 1) (enumera 10 50 10))((1 10) (2 20) (3 30) (4 40) (5 50))

Mais interessante será uma combinação entre uma enumeração e uma pa-rameterização. Para que ambas gerem o mesmo número de valores é maissimples usarmos as variantes enumera-n e parametrica-n. Por exemplo:25

_$ (mapeia2 xy (enumera-n 1 5 4) (parametrica-n sin 0 2*pi 4))((1.0 0.0) (2.0 1.0) (3.0 0.0) (4.0 -1.0) (5.0 0.0))

O resultado poderia agora ser injectado directamente na função spline-pontospara representar graficamente a sinusóide.

Ainda mais flexível será a combinação de duas parameterizações, uma emX e a outra em Y . Um caso óbvio é o da circunferência de raio unitário. Dadoque esta curva pode ser definida parametricamente através de

x(t) = cos t

y(t) = sin t

podemos simplesmente gerar esta curva no AutoCad através de duas param-eterizações independentes—um cosseno em X e um seno em Y—que combi-namos numa sequência de coordenadas:

25Os resultados encontram-se ligeiramente arredondados para melhor se perceberem.

71

(spline-pontos(mapeia2 xy

(parametrica-n cos 0 2*pi 100)(parametrica-n sin 0 2*pi 100)))

Embora, no caso anterior, ambas as parameterizações cubram o mesmointervalo de valores, nomeadamente, entre 0 e 2π, nada obriga a que assimseja. Por exemplo, se pretendermos “dilatar” o gráfico de um seno dispostoao longo do eixo do X à medida que nos afastamos da origem, podemos sim-plesmente empregar uma função exponencial para a parameterização em X ,i.e.:

(spline-pontos(mapeia2 xy

(parametrica-n exp (log 1) (log 10) 100)(parametrica-n quadrado 1 10 100)))

Se, pelo contrário, quisermos “comprimir” o gráfico de um seno, podemosempregar uma função logarítmica em X , i.e.:

(spline-pontos(mapeia2 xy

(parametrica-n log (exp 1) (exp 10) 100)(parametrica-n sin 0 (* 8 pi) 100)))

A generalização dos três últimos exemplos sugere-nos a criação de umafunção onde as parameterizações em X e Y são, elas próprias, parâmetrosda função. Para isso, vamos considerar os parâmetros fy—representando afunção a parameterizar em Y—e fx e f−1

x —representando a função a usar paraparameterizar em X e a sua função inversa necessária para calcular os limitesapropriados da parameterização a partir dos limites [x0, x1]. Para podermoslocalizar o gráfico de uma função num ponto arbitrário do plano, vamos tam-bém considerar este ponto como parâmetro:

(defun grafico (p fy fx fx-1 x0 x1 n)(spline-pontos(mapeia2 (lambda (x y)

(+xy p x y))(parametrica-n fx (fx-1 x0) (fx-1 x1) n)(parametrica-n fy x0 x1 n))))

As seguintes expressões constituem um exemplo do uso desta função:

(grafico (xy 0 8) sin identidade identidade 0 (* 6 pi) 100)(grafico (xy 0 4) sin sqrt quadrado 0 (* 6 pi) 100)(grafico (xy 0 0) sin quadrado sqrt 0 (* 6 pi) 100)

O gráfico produzido por elas encontra-se representado na Figura 33.

Exercício 2.14.1 Para melhor se perceberem os gráficos poderá ser útil associar aos mesmosuma “malha” que indique a escala que foi empregue em cada um. Para isso, podemos desenharum determinado número de linhas rectas emX e Y que serão espaçadas de acordo com a escalado gráfico, tal como se apresenta na imagem seguinte:

72

Figura 33: Sinusóides normais, dilatadas e comprimidas ao longo do eixo Xapenas através da especificação de uma “escala” não linear ao longo deste eixo.

Redefina a função grafico de modo a que ela receba mais dois parâmetros que represen-tam o número de linhas em X e Y e que traça esse número de linhas de acordo com a escala dográfico.

73