Was ist in Haskell der Unterschied zwischen der Verwendung von takeWhile oder einer „regulären“ Ungleichung in diesem Listenverständnis?

Ich versuche, mir ein Haskell beizubringen (zum Wohle des Guten), und eine der vielen verschiedenen Aufgaben, die ich mache, besteht darin, einige Probleme mit Project Euler in Angriff zu nehmen, während ich meine Fähigkeiten teste.

Bei einigen der auf Fibonacci basierenden Probleme bin ich auf die rekursive Endloslistenversion der Fibonacci-Sequenz gestoßen und habe angefangen, damit herumzuspielen:

fibs = 1 : 2 : zipWith (+) fibs (tail fibs)

Für eines der PE-Probleme musste ich die Teilsequenz von Fibonacci-Zahlen mit weniger als 4.000.000 extrahieren. Ich beschloss, dies mit einem Listenverständnis zu tun, und stolperte beim Herumspielen mit dem Code über etwas, das ich nicht ganz verstehe. Ich gehe davon aus, dass es mein schwaches Verständnis von Haskells faulem Bewertungsschema ist, das die Dinge kompliziert.

Das folgende Verständnis funktioniert einwandfrei:

[x | x <- takeWhile (<= 4000000) fibs, even x]

Das nächste Verständnis dreht sich für immer; Also ging ich durch und ließ die Ausgabe auf stdout zurückkehren, und während sie an der richtigen Stelle stoppt, scheint sie die rekursiv definierte Liste für immer auszuwerten, ohne nach Erreichen des begrenzten Werts fertig zu werden. Dies weist darauf hin, dass das letzte Element in der Liste mit einem Komma gedruckt wird, aber keine weiteren Listenelemente oder schließenden eckigen Klammern vorhanden sind:

[x | x <- fibs, x <= 4000000, even x]

Also, was genau ist die geheime Sauce, die von den verschiedenen Funktionen verwendet wird, die gut mit unendlichen Listen funktionieren?

Antworten auf die Frage(1)

Ihre Antwort auf die Frage