Você está na página 1de 6

http://www.dca.fee.unicamp.br/courses/EA072/lisp9596/Lisp9596.html Expresses Condicionais Existem muitas operaes cujo resultado depende da realizao de um determinado teste.

Por exemplo, a funo matemtica abs--que calcula o valor absoluto de um nmero--equivale ao prprio nmero, se este positivo, ou equivale ao seu simtrico se for negativo. Estas expresses, cujo valor depende de um ou mais testes a realizar previamente, permitindo escolher vias diferentes para a obteno do resultado, so designadas expresses condicionais. No caso mais simples de uma expresso condicional, existem apenas duas alternativas a seguir. Isto implica que o teste que necessrio realizar para determinar a via de clculo a seguir deve produzir um de dois valores, em que cada valor designa uma das vias. Seguindo o mesmo racioccio, uma expresso condicional com mais de duas alternativas dever implicar um teste com igual nmero de possveis resultados. Uma expresso da forma ``caso o valor do teste seja 1, 2 ou 3, o valor da expresso 10, 20 ou 30, respectivamente'' um exemplo desta categoria de expresses que, embora seja considerada pouco intuitiva, existe nalgumas linguagens (Basic, por exemplo). Contudo, estas expresses podem ser facilmente reduzidas primeira. Basta decompor a expresso condicional mltipla numa composio de expresses condicionais simples, em que o teste original tambm decomposto numa srie de testes simples. Assim, poderiamos transformar o exemplo anterior em: ``se o valor do teste 1, o resultado 10, caso contrrio, se o valor 2, o resultado 20, caso contrrio 30''. Predicados

Desta forma, reduzimos todos os testes a expresses cujo valor pode ser apenas um de dois, e a expresso condicional assume a forma de ``se ...ento ...caso contrrio ...''. Nesta situao, a funo usada como teste denominada predicado e o valor do teste interpretado como sendo verdadeiro ou falso. Nesta ptica, o facto de se considerar o valor como verdadeiro ou falso no implica que o valor seja de um tipo de dados especial, como o booleano ou lgico de algumas linguagens (como o Pascal), mas apenas que a expresso condicional considera alguns dos valores como representando o verdadeiro e os restantes como o falso. Em Lisp, as expresses condicionais consideram como falso um nico valor. Esse valor representado por nil. Qualquer outro valor diferente de nil considerado como verdadeiro. Assim, do ponto de vista de uma expresso condicional, qualquer nmero um valor verdadeiro. Contudo, no faz muito sentido para o utilizador humano considerar um nmero como verdadeiro ou falso, pelo que se introduziu uma constante na linguagem para representar verdade. Essa constante representa-se por t. Note-se que, se t diferente de nil, e se nil o nico valor que representa a falsidade, ento t representa verdade. Desta forma, existem muitos predicados em Lisp cujo valor t quando a expresso por eles designada considerada verdadeira. > (> 4 3) t > (< 4 3) nil Existem muitos predicados em Lisp. Os predicados numricos mais usados so o zerop, =, >, <, >=, <=. O zerop testa se um nmero zero ou diferente de zero. > (zerop 1) nil > (zerop 0) t O facto de zerop terminar com a letra ``p'' deve-se a uma conveno adoptada em Common Lisp segundo a qual os predicados devem ser distinguidos das restantes funes atravs da concatenao da letra ``p'' (de predicate) ao seu nome. Apesar da adopo dos smbolos t e nil, convm alertar que nem todos os predicados devolvem t ou nil exclusivamente. Alguns h que, quando querem indicar verdade, devolvem valores diferentes de t (e de nil, obviamente). Operadores Lgicos

Para se poder combinar expresses lgicas entre si existem os operadores and, or e not. O and e o or recebem qualquer nmero de argumentos. O not s recebe um. O valor das combinaes que empregam estes operadores lgicos determinado do seguinte modo:

O and avalia os seus argumentos da esquerda para a direita at que um deles seja falso, devolvendo este valor. Se nenhum for falso o and devolve o valor do ltimo argumento. O or avalia os seus argumentos da esquerda para a direita at que um deles seja verdade, devolvendo este valor. Se nenhum for verdade o or devolve o valor do ltimo argumento. O not avalia para verdade se o seu argumento for falso e para falso em caso contrrio. Note-se que embora o significado de falso seja claro pois corresponde necessariamente ao valor nil, o significado de verdade j no to claro pois, desde que seja diferente de nil, considerado verdade. Exerccio 6 Qual o valor das seguintes expresses? (and (or (> 2 3) (not (= 2 3))) (< 2 3)) (not (or (= 1 2) (= 2 3))) (or (< 1 2) (= 1 2) (> 1 2)) (and 1 2 3) (or 1 2 3) (and nil 2 3) (or nil nil 3) Resposta: T T T 3 1 nil 3 Seleco simples

O if a expresso condicional mais simples do Lisp. O if determina a via a seguir em funo do valor de uma expresso lgica. A sintaxe do if : (if condio consequente alternativa) Para o if, a condio o primeiro argumento, o consequente no caso de a condio ser verdade o segundo argumento e a alternativa no caso de ser falso o terceiro argumento. > (if (> 4 3) 5 6) 5 Uma expresso if avaliada determinando o valor da condio. Se ela for verdade, avaliado o consequente. Se ela for falsa avaliada a alternativa. Exerccio 7 Defina uma funo soma-grandes que recebe trs nmeros como argumento e determina a soma dos dois maiores. Resposta (defun soma-grandes (x y z) (if (>= x y) (if (>= y z) (+ x y) (+ x z)) (if (< x z) (+ y z) (+ x y)))) Exerccio 8 Escreva uma funo que calcule o factorial de um nmero. (defun fact (n) (if (zerop n) 1 (* n (fact (- n 1)))))

A funo fact um exemplo de uma funo recursiva, i.e., que se refere a ela prpria. Seleco Mltipla Para alm do if, existem outras expresses condicionais em Lisp. O cond uma verso mais potente que o if. uma espcie de switch-case do C. A sua sintaxe : (cond (condio-1 expresso-1) (condio-2 expresso-2) (condio-n expresso-n)) Designa-se o par (condio-i expresso-i) por clusula. O cond testa cada uma das condies em sequncia, e quando uma delas avalia para verdade, devolvido o valor da expresso correspondente, terminando a avaliao. Um exemplo ser: > (cond ((> 4 3) 5) (t 6)) 5 O cond permite uma anlise de casos mais simples do que o if. (defun teste (x y z w) (cond ((> x y) z) ((< (+ x w) (* y z)) x) ((= w z) (+ x y)) (t 777))) A funo equivalente usando if seria mais complicada. (defun teste (x y z w) (if (> x y) z (if (< (+ x w) (* y z)) x (if (= w z) (+ x y) 777)))) Formas Especiais Dada a similitude entre o if e o cond lcito perguntar se precisaremos dos dois. Ser que no possvel definir um em termos do outro ? A seguinte definio parece ser uma resposta: > (defun meu-if (condicao consequente alternativa) (cond (condicao consequente) (t alternativa))) meu-if > (meu-if (> 4 3) 5 6) 5 > (meu-if (> 3 4) 5 6) 6 Quando testamos o meu-if, tudo parece bem. No entanto, se escrevermos um exemplo ligeiramente diferente, algo corre mal. > (defun divide (x y) (meu-if (zerop y) 0 (/ x y))) divide > (divide 2 0) Error:..... O que que est a acontecer? Tentemos seguir as regras do avaliador para explicar a situao. A avaliao de combinaes implica a aplicao da funo--que o primeiro elemento da combinao--aos valores dos restantes elementos. No exemplo (divide 2 0), a aplicao da funo divide ao valor de 2 e 0 o valor da combinao (meu-if (zerop 0) 0 (/ 2 0)), que a aplicao da funo meu-if ao valor de (zerop 0) que t, 0 que vale 0 e (/ 2 0) que um erro pois no se pode dividir 2 por 0. Desta forma, a funo meu-if avalia o seu ltimo argumento cedo demais, no esperando pelo valor de (zerop 0) para saber se pode avaliar (/ 2 0). Mas h situaes piores. Consideremos a seguinte definio e aplicao da funo factorial. > (defun meu-fact (n)

(meu-if (zerop n) 1 (* n (meu-fact (- n 1))))) meu-fact > (meu-fact 4) Error:..... Nesta situao, a avaliao de combinaes implica a aplicao da funo que o primeiro elemento da combinao aos valores dos restantes elementos. No exemplo (meu-fact 4), a aplicao da funomeu-fact ao valor de 4 o valor da combinao (meu-if (zerop 4) 1 (* 4 (meu-fact (- 4 1)))), que a aplicao da funo meu-if ao valor de (zerop 4) que nil , 1 que vale 1 e (meu-fact 3) que a aplicao da funo meu-fact ao valor 3, que o valor da combinao... Desta forma, a funo meu-if no chega sequer a completar a avaliao dos seus argumentos, no podendo determinar qual dos valores, consequente ou alternativa, retornar, repetindo indefinidamente a aplicao da funo meu-fact a argumentos sucessivamente decrescentes. Suponhamos agora a seguinte interaco com o Lisp: > (if (> 4 3) 100 (inexistente)) 100 Segundo o modelo de avaliao que tnhamos apresentado, uma combinao avaliada aplicando o procedimento que o primeiro elemento da combinao especifica ao valor dos restantes elementos. Nesta ptica, antes de se escolher a opo a seguir, o avaliador deveria avaliar todas elas, i.e., 100 cujo valor 100 e a aplicao da funo inexistente que devia produzir um erro pois a funo ainda no foi definida. Porque ser que quando testamos isto no produzido nenhum erro? evidente que, de algum modo, o if no seguiu as regras do modelo de avaliao de combinaes, caso contrrio, teria mesmo produzido um erro. Isto sugere que if no uma funo normal mas sim algo que possui a sua prpria regra de avaliao. Uma forma especial uma expresso da linguagem que possui a sua prpria sintaxe e a sua prpria regra de avaliao. de salientar que uma forma especial no uma funo. Ela faz parte da estrutura do avaliador e no do seu ambiente. O defun, o if e o cond so algumas das formas especiais. Mas o and e o or tambm so, pois s avaliam os operandos que forem necessrios para determinar o resultado. O and pra de avaliar quando um deles produzir falso, o or quando um deles produzir verdade. Como uma forma especial possui a sua prpria regra de avaliao, nem tudo o que se faz com uma funo se pode fazer com uma forma especial, e nem tudo o que se faz com uma forma especial se pode fazer com uma funo. Ao contrrio das outras linguagens que possuem muitas formas especiais, Lisp tem muito poucas. Desta forma, a linguagem possui uma regra de avaliao muito simples e muito bem definida, e em que as pequenas excepes so implementadas pelas formas especiais. No entanto, e ao contrrio do que acontece na maioria das outras linguagens, Lisp permite ao utilizador definir novas formas cujo comportamento semelhante ao das formas especiais. Isso feito atravs de macros, que so formas que so transformadas noutras formas (especiais ou no) durante a interpretao ou a compilao. Funes Recursivas Uma funo recursiva uma funo que se refere a si prpria. A ideia consiste em utilizar a prpria funo que estamos a definir na sua definio. Em todas as funes recursivas existe: Um passo bsico (ou mais) cujo resultado imediatamente conhecido. Um passo recursivo em que se tenta resolver um sub-problema do problema inicial. Se analisarmos a funo factorial, o caso bsico o teste de igualdade a zero (zerop n), o resultado imediato 1, e o passo recursivo (* n (fact (- n 1))). Geralmente, uma funo recursiva s funciona se tiver uma expresso condicional, mas no obrigatrio que assim seja. A execuo de uma funo recursiva consiste em ir resolvendo subproblemas sucessivamente mais simples at se atingir o caso mais simples de todos, cujo resultado imediato. Desta forma, o padro mais comum para escrever uma funo recursiva : Comear por testar os casos mais simples. Fazer chamada (ou chamadas) recursivas com subproblemas cada vez mais prximos dos casos mais simples. Dado este padro, os erros mais comuns associados s funes recursivas so, naturalmente: No detectar os casos simples A recurso no diminuir a complexidade do problema.

No caso de erro em funo recursivas, o mais usual a recurso nunca parar. O nmero de chamadas recursivas cresce indefinidamente at esgotar a memria (stack), e o programa gera um erro. Em certas linguagens (Scheme) e implementaes do Common Lisp, isto no assim, e pode nunca ser gerado um erro. A recurso infinita o equivalente das funes recursivas aos ciclos infinitos dos mtodos iterativos do tipo while-do e repeat-until. Repare-se que uma funo recursiva que funciona perfeitamente para os casos para que foi prevista pode estar completamente errada para outros casos. A funo fact um exemplo. Quando o argumento negativo, o problema torna-se cada vez mais complexo, cada vez mais longe do caso simples. (fact -1) => (fact -2) => (fact -3) => Exerccio 9 Considere uma verso extremamente primitiva da linguagem Lisp, em que as nicas funes numricas existentes so zerop e duas funes que incrementam e decrementam o seu argumento em uma unidade, respectivamente, 1+ e 1-. Isto implica que as operaes >, <, = e similares no podem ser utilizadas. Nesta linguagem, que passaremos a designar por nanoLisp, abreviadamente nanoLisp , defina o predicado menor, que recebe dois nmero inteiros positivos e determina se o primeiro argumento numericamente inferior ao segundo. Resposta (defun menor (x y) (cond ((zerop y) nil) ((zerop x) t) (t (menor (1- x) (1- y))))) Exerccio 10 Defina a operao igual? que testa igualdade numrica de inteiros positivos na linguagem nanoLisp . Resposta (defun igual? (x y) (cond ((zerop x) (zerop y)) ((zerop y) nil) (t (igual? (1- x) (1- y))))) Exerccio 11 At ao momento, a linguagem nanoLisp apenas trabalha com nmeros inteiros positivos. Admitindo que as operaes 1+, 1- e zerop tambm funcionam com nmeros negativos, defina a funonegativo que recebe um nmero inteiro positivo e retorna o seu simtrico. Assim, pretendemos obter: (negativo 3) => -3. Resposta (defun negativo (x) (if (zerop x) x (1- (negativo (1- x)))) Exerccio 12 Agora que a linguagem nanoLisp pode tambm trabalhar com nmeros inteiros negativos, defina o predicado positivo?, que recebe um nmero e indica se ele positivo ou no. Resposta (defun positivo? (x) (positivo-aux x x)) (defun positivo-aux (x+ x-) (cond ((zerop x-) t) ((zerop x+) nil) (t (positivo-aux (1+ x+) (1- x-))))) Exerccio 13 Defina o teste de igualdade de dois nmeros na linguagem nanoLisp contemplando a possibilidade de trabalhar tambm com nmeros inteiros negativos. Resposta (defun igual? (x y) (igual-aux x x y y)) (defun igual-aux (x+ x- y+ y-) (cond ((zerop x+) (zerop y+)) ((zerop x-) (zerop y-)) ((or (zerop y+) (zerop y-)) nil)

(t (igual-aux (1+ x+) (1- x-) (1+ y+) (1- y-)))))

Você também pode gostar