Qual é a explicação para o Exercício 1.6 no SICP?
Pergunta
Estou apenas começando a trabalhar no SICP (por conta própria; isso não é para uma aula), e tenho lutado com o Exercício 1.6 há alguns dias e eu simplesmente não consigo descobrir. Este é o que Alyssa redefina if
em termos de cond
, igual a:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause))
Ela o testa com sucesso em alguns casos simples e depois o usa para reescrever o programa Square Root (que funcionou bem com if
):
(define (sqrt-iter guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
A pergunta então pergunta: "O que acontece quando Alyssa tenta usar isso para calcular raízes quadradas? Explique". [Se necessário, fico feliz em reproduzir os outros procedimentos (good-enough?
, improve
, etc.), apenas me avise.
Agora, eu sei o que acontece: ele nunca retorna um valor, o que significa que o programa recorre infinitamente. Eu simplesmente não consigo explicar por que isso acontece. Qualquer que seja a diferença sutil entre if
e new-if
está me iludindo. Todo e qualquer ajuda muito apreciado.
Solução
new-if
é uma função. Quando uma função é chamada, qual é a primeira coisa que o esquema faz com a lista de argumentos? Avalia tudo os argumentos.
Outras dicas
new-if
é um procedimento e o esquema usa a avaliação de ordem de aplicação (1.1.5), portanto, mesmo antes de new-if
é realmente realizado, ele tem que avaliar todos os argumentos primeiro, que são guess
e (sqrt-iter (improve guess x) x)
. Você pode ver que o último argumento é uma recursão, que chama de um novo new-if
Procedimento, é assim que ocorre o loop infinito.
O comum if
não precisa avaliar seus argumentos primeiro, apenas siga o caminho, essa é a diferença entre if
e new-if
. :)
Primeiro de tudo, você tem que entenda a diferença entre avaliação de pedidos aplicativos e ordem normal. O LISP usa a ordem aplicativa, mas expressões condicionais são avaliadas não como funções normais (SICP Capítulo 1.1.6):
(if <predicate> <consequent> <alternative>)
Para avaliar uma expressão IF, o intérprete começa avaliando o
<predicate>
parte da expressão. Se o<predicate>
avalia um valor verdadeiro, o intérprete avalia o<consequent>
e retorna seu valor. Caso contrário, avalia o<alternative>
e retorna seu valor.
Ex1.6. novo-se:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
Diferença com 'if -states': se as states se avaliam uma a uma de predicada -> consequente -> alternativa,
No entanto, o 'novo-if' precisa avaliar todos os parâmetros, também conhecidos como argumentos, no momento em que é chamado (que significa 'outra cláusula' é avaliado no início !!),
E assim isso causa um loop infinito quando algum desses parâmetros se chama para um loop iterativo