Ich fange gerade an, SICP durchzuarbeiten (alleine; dies ist nicht für eine Klasse), und ich habe seit ein paar Tagen mit Übung 1.6 zu kämpfen, und ich kann es einfach nicht herausfinden. Dies ist derjenige, den Alyssa neu definiert if
in Bezug auf cond
:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause))
Sie testet es erfolgreich in einigen einfachen Fällen und verwendet es dann, um das Quadratwurzelprogramm neu zu schreiben (was gut funktioniert hat if
):
(define (sqrt-iter guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
Die Frage lautet dann: "Was passiert, wenn Alyssa versucht, damit Quadratwurzeln zu berechnen? Erklären Sie." [Falls nötig, ich bin glücklich , die anderen Verfahren zu reproduzieren ( good-enough?
, improve
usw.), lassen Sie es mich wissen.]
Jetzt weiß ich, was passiert: Es gibt niemals einen Wert zurück, was bedeutet, dass das Programm unendlich rekursiv ist. Ich kann einfach nicht erklären, warum das passiert. Was auch immer feiner Unterschied besteht zwischen if
und new-if
ist eluding ich. Jede Hilfe wird sehr geschätzt.
quelle
Antworten:
new-if
ist eine Funktion. Was macht Scheme beim Aufruf einer Funktion als erstes mit der Argumentliste? Es wertet alle Argumente aus.quelle
new-if
ist ein Verfahren, und das Schema verwendet die Bewertung der anwendbaren Reihenfolge (1.1.5). Bevornew-if
es tatsächlich durchgeführt wird, muss es zuerst alle Argumente bewerten, nämlichguess
und(sqrt-iter (improve guess x) x)
. Sie können sehen, dass das letztere Argument eine Rekursion ist, die eine neuenew-if
Prozedur aufruft. So tritt die Endlosschleife auf.Das Gewöhnliche
if
muss seine Argumente nicht zuerst bewerten, sondern nur den Weg gehen, dies ist der Unterschied zwischenif
undnew-if
. :) :)quelle
new-if
Verfahren hat drei Argumente:predicate
,then-clause
undelse-clause
. Wenn alsonew-if
heißt,(good-enough? guess x)
,guess
, und(sqrt-iter (improve guess x))
werden ausgewertet. Ist das richtig ? Dies ändert nichts am Ergebnis, da nur die Bewertungsqrt-iter
der Probleme verursacht. Aber imo hast du ein Argument vergessen ...Zunächst müssen Sie den Unterschied zwischen der Bewertung der anwendbaren Bestellung und der normalen Bestellung verstehen . Lisp verwendet die anwendbare Reihenfolge, aber bedingte Ausdrücke werden nicht wie normale Funktionen ausgewertet ( sicp Kapitel 1.1.6 ):
quelle
Es gibt drei Möglichkeiten, wie ein Formular im Schema bewertet werden kann:
f(x)=x+x
:3*f(1)*f(1)
⇒3*2*2
f(x)=x+x
:3*f(1)*f(1)
⇒3*(1+1)*(1+1)
(auch in "Lazy Evaluation" verwendet)and
undor
. Zum Beispiel:(and <e1> ... <en>)
wertet Links → Rechts aus. Wenn einer Wert als falsch ausgewertet wird, ist der Wert von und Ausdruck falsch, und die übrigen Werte<e>
werden nicht ausgewertet.if
undcond
(if <predicate> <consequent> <alternative>)
: Wenn der<predicate>
Wert einen wahren Wert ergibt, wertet der Interpreter den<consequent>
Wert aus und gibt seinen Wert zurück. Andernfalls wertet es das aus<alternative>
und gibt seinen Wert zurück(cond (<p1> <e1>) ... (<pn> <en>))
: Das Prädikat<p1>
wird zuerst ausgewertet. Wenn sein Wert falsch ist,<pn>
wird ausgewertet. Wenn<pn>
der Wert ebenfalls falsch ist,<pn+1>
wird er ausgewertet. Bei wahrem Prädikat gibt der Interpreter den Wert des entsprechenden nachfolgenden Ausdrucks zurück<e>
.Im Fall von Übung 1.6:
new-if
ist ein normales Verfahren. In Scheme (und vielen anderen Sprachen) werden Argumente vollständig ausgewertet, bevor die Prozedur aufgerufen wird. Dies wird als anwendbare Reihenfolge bezeichnet . ∴sqrt-iter
wird jedes Malnew-if
aufgerufen, was zu einer Endlosschleife führt.if
s eine spezielle Form . Die rekursive Anweisung wird nur ausgewertet, wenn die<alternative>
aufgerufen wird.quelle
Frühere Antworten sind großartig. Ich werde eine weitere hinzufügen, die ausführlicher erklärt.
Eine andere Art, sich diesen Unterschied vorzustellen, ist folgende : Wie wird die Rekursion verwendet
if
, indem irgendwann gestoppt wird, und die Rekursion, die für immer einenew-if
Schleife verwendet?Zuerst werden wir sehen , wie diese beiden , wenn die Arbeit im Allgemeinen und dann , wie sie für diesen Fall arbeiten.
if
Dies wird durch @ alex-vasi erklärt :
new-if
Dies wird von @Schmudde erklärt :
Wie wird die Rekursion verwendet
if
, um irgendwann anzuhalten?Es hört auf, weil wir an dem Punkt, an dem
guess
das gut genug ist (dh(good-enough? guess x)
isttrue
), haben werden:Und da das
predicate
jetzt isttrue
, wertet der Interpreter dasconsequent
(was istguess
) aus, gibt seinen Wert zurück und bewertet dasalternative
(was ist(sqrt-iter (improve guess x) x)
) nicht mehr .Also
if
tatsächlich(sqrt-iter (improve guess x) x)
rekursiv auswerten bis dasguess
gut genug ist. Dann stoppt es die Rekursion.Wie ist die Rekursion mit
new-if
Looping für immer?Wie bei
if
wird mitnew-if
(sqrt-iter (improve guess x) x)
rekursiv ausgewertet, bis dasguess
gut genug ist.Aber dann wird es immer
(sqrt-iter (improve guess x) x)
wieder ausgewertet . Warum? Denn bei der Bewertung:Da
new-if
es sich um eine Prozedur handelt, wird nicht geprüft, ob sie(good-enough? guess x)
wahr ist oder nicht, um zu entscheiden, ob entwederguess
oder bewertet werden soll(sqrt-iter (improve guess x))
. Was es tun wird, ist, dass es ausgewertet wird(good-enough? guess x)
,guess
und(sqrt-iter (improve guess x))
weil dies die Argumente des Verfahrens sind. Selbst wennguess
es gut genug ist, wird es immer wieder(sqrt-iter (improve guess x))
rekursiv aufgerufen: /.quelle
Ex1.6. neu-wenn:
Unterschied zu 'if-Anweisungen': if-Anweisungen werden einzeln anhand des Prädikats -> konsequent -> alternativ ausgewertet,
Das 'new-if' muss jedoch alle Parameter auswerten, auch bekannt als Argumente, die der MOMENT aufgerufen hat (was bedeutet, dass 'else-Klausel' zu Beginn ausgewertet wird !!).
und somit verursacht dies eine Endlosschleife, wenn sich einer dieser Parameter in eine iterative Schleife aufruft
quelle