quinta-feira, 27 de agosto de 2009

Predicados de Equivalência

Um predicado é um procedimento que sempre devolve um valor booleano (#t ou #f) .Um predicado de equivalência é a analogia computacional de uma relação de equivalência matemática (é simétrico, reflexivo, e transitivo). Dos predicados de equivalência descritos nesta seção, eq? é o discriminando melhor , e equal? é ligeiramente menos distintivo do que eq?.
procedimento essencial: eqv? obj1 obj2
O procedimento define uma relação de equivalência útil em objetos. eqv? Rapidamente, retorna #t se obj1 e obj2 deveriam ser normalmente como o mesmo objeto. Esta relação permanece ligeiramente aberta a interpretações, mas a especificação parcial de eqv? demonstra todas as implementações em Scheme.
O procedimento eqv? devolve #t se:
  • obj1 e obj2 são ambos #t ou ambos #f.
  • obj1 e obj2 são símbolos e
(string=? (symbol->string obj1)
  (symbol->string obj2))
 => #t
Nota: Isto assume que nem obj1 nem obj2 não são um " símbolo interminável" como aludiu para a seção Simbolos. Este página não presume em especificar o comportamento de eqv? em extensões implementação-dependentes.
  • obj1 e obj2 são ambos números, numericamente se igualam, e são ambos exatos ou inexatos.
  • obj1 e obj2 são ambos caracteres e são o mesmo caracter de acordo com o procedimento char=?
  • ambos obj1 e obj2 são a lista vazia.
  • obj1 e obj2 são pares, vetores, ou strings que denotam as mesmas localizações no armazenamento.
  • obj1 e obj2 são procedimentos cujas tags de localização são iguais.
O procedimento eqv? devolve #f se:
  • obj1 e obj2 são de tipos diferentes
  • um de obj1 e obj2é #t mas o outro é #f .
  • obj1 e obj2 são símbolos mas
(string =? (symbol->string obj1)
  (symbol->string obj2))
  = #f
  • um de obj1 e obj2 é um número exato mas o outro é um número inexato.
  • obj1 e obj2 são números para os quais procedimento = retorna #f
  • obj1 e obj2 são caracteres para qual o procedimento char=? retorna #f
  • um de obj1 e obj2é a lista vazia mas o outro não é.
  • obj1 e obj2 são pares, vetores, ou strings que denotam localizações distintas.
  • obj1 e obj2 são procedimentos que se comportariam diferentemente (retornam um valor diferente ou tem efeitos colaterais diferentes) para alguns argumentos.
(eqv? ' a ' a)   = #t
 (eqv? ' a ' b)   = #f
 (eqv? 2 2)    = #t
 (eqv? ' () ' ())   = #t
 (eqv? 100000000 100000000) = #t
 (eqv? (cons 1 2) (cons 1 2)) = #f
 (eqv? (lambda () 1)
       (lambda () 2))  = #f
 (eqv? #f ' nil)   = #f
 (let ((p (lambda (x) x)))
  (eqv? p p))   = #t
Os exemplos seguintes ilustram casos nos quais as regras acima não especificam completamente o comportamento de eqv? Tudo o que pode ser dito sobre tais casos é que o valor retornado por eqv? deve ser um booleano.
(eqv? """") = unspecified
 (eqv? ' #() ' #()) = unspecified
 (eqv? (lambda (x) x)
  (lambda (x) x)) = unspecified
 (eqv? (lambda (x) x)
  (lambda (y) y)) = unspecified
O próximo conjunto de exemplos usa eqv? com procedimentos que têm estado local. Gen-counter deve retornar um procedimento distinto toda vez, desde que cada procedimento tenha seu próprio contador interno. Gen-loser, porém, trata procedimentos equivalentes cada tempo, desde que o estado local não afete o valor ou provoque efeitos colaterais nos procedimentos.
(define gen-contador
    (lambda ()
   (let ((n 0))
    (lambda () (set! n (+ n 1)) n))))
 (let ((g (gen-counter)))
  (eqv? g g))
 (eqv? (gen-counter (gen-counter)) = #f

 (define o gen-perdedor
  (lambda ()
   (let ((n 0))
    (lambda () (let! n (+ n 1)) 27))))
 (let ((g (g gen-perdedor)))
  (eqv? g g)) = #t
 (eqv? (o gen-loser) (gen-loser)) = unspecified

 (letrec ((f (lambda () (if (eqv? f g) ' both ' f)))
  (g (lambda () (se (eqv? f g) ' both ' g)))
 (eqv? f g)) = unspecified

 (letrec ((f (lambda () (if (eqv? f g) ' f ' both)))
  (g (lambda () (if (eqv? f g) ' g ' both)))
 (eqv? f g)) = #f
Como ele deve modificar objetos constantes por um erro (esses devolvidos por expressões literais), são permitidas (no entanto não exigidas) às implementações compartilhar estruturas entre constantes quando apropriadas. Assim o valor de eqv? em constantes às vezes é dependente da implementação.
 (eqv? ' (a) ' (a)) = unspecified
 (eqv? "a"  "a") = unspecified
 (eqv? ' (b) (cdr ' (a b))) = unspecified
 (let ((x ' (a)))
 (eqv? x x)) = #t
Razão: A definição acima de eqv? permite maior liberdade na implementação no tratamento de procedimentos e literais: implementações são livres para detectar falhas ou descobrir que dois procedimentos ou dois literais são equivalentes um ao outro, e pode decidir se deve ou não fundir representações de objetos equivalentes usando o mesmo ponteiro ou paleta de bits para representar ambos.

Nenhum comentário: