Warum weigert sich GHC manchmal, faul zu sein?

8

Dies geht in eine Endlosschleife auf tryhaskell.org. Ich bin mir nicht sicher warum.

%Vor%     
Vanson Samuel 02.09.2011, 17:41
quelle

2 Antworten

9

Es ist nicht ablehnend, faul zu sein, es gibt einfach keine Möglichkeit es zu wissen, nachdem du alle Primzahlen bekommen hast & lt; 100, gibt es nicht mehr.

Was wäre, wenn die Sequenz wie

aussieht?

1, 2, ... 99, 100, 101, 102, 5, 103, ...

Mit anderen Worten, last kann die Zukunft nicht vorhersagen. Oh, wie ich es mir wünsche.

    
Owen 02.09.2011, 17:47
quelle
9

Lasst uns die Dinge auseinander nehmen, von innen heraus arbeiten. Ausgehend davon:

%Vor%

Betrachten Sie zuerst map (mod a) [2..a-1] . Dies ist nur eine Transformation einer endlichen Liste, also keine Probleme hier, und wir werden sie von hier an ignorieren, indem wir [..] an ihre Stelle setzen. Da wir uns nur um die Terminierung kümmern, ist jede endliche Liste so gut wie eine andere.

Gleiches gilt für filter (== 0) [...] . Dies kann die Liste nur verkleinern, so dass wir stattdessen eine leere Liste haben, die aber endlich ist. Also ignorier das auch. Betrachten wir nun length [..] - wir wissen, dass die Liste endlich ist, also wird dies gut enden und eine Antwort von 0 oder mehr geben. Wir ignorieren die spezifische Antwort und setzen ? an ihre Stelle. Bis jetzt noch in Ordnung.

Das Lambda \a -> if 0 == ? then return a else [] verwendet return in der Liste monad, so dass a entweder durch [a] oder [] ersetzt wird, was übrigens Maybe entspricht, aber das ist eine andere Sache. Auch hier wissen wir, dass so viel funktioniert, also ignorieren wir die Details und verwenden \a -> [a?] .

Die monadische Bindung [2..] >>= \a -> [a?] ist interessanter. (>>=) ist hier concatMap und das erste Argument ist eine unendliche Liste. Mapping jedes Element zu einer Singleton-Liste und Verkettung ändert offensichtlich nichts, während die Zuordnung zu der leeren Liste ein Element entfernt, so ist dies im Wesentlichen nur filter . Dinge sind nicht so einfach hier, weil wir eine unendliche Liste filtern, ohne offensichtliche Gewissheit, dass alles den Filter passieren wird . Wenn Sie filter (const False) [0..] ausführen, enthält das "Ergebnis" keine Elemente, aber die Berechnung wird niemals abgeschlossen. Die [] in der Ausgabe von filter ergibt sich aus dem Finden des Endes der Eingabeliste, und dies hat keine, und da es niemals ein erstes Element finden wird, ist das Ergebnis nur _|_ .

Also sind die Dinge schon problematisch. Der nächste Teil, filter (<100) , macht die Sache noch schlimmer - wir filtern Elemente aus einer streng ansteigenden Liste und filtern sie dann, wenn sie unter einem Wert liegen, also nach dem obigen Argument, wenn wir 100 in der Ergebnis wird die Berechnung hängen.

Und die letzte Beleidigung ist last - die fragliche Liste ist immer noch unendlich, wird aber irgendwann divergieren, anstatt mehr Elemente zu erzeugen. Wenn wir also nach dem letzten Element fragen, können wir sehen, dass es nicht enden wird aus mehreren Gründen!

Was Sie hier tun möchten, ist zunächst, dass Sie Ihr Wissen anwenden, dass die Liste streng zunimmt, und statt Filtern die Liste, nehmen Sie einfach ein Präfix bis zum gewünschten Punkt-- zB takeWhile (<100) anstatt filter (< 100) . Beachten Sie, dass dies immer noch abweichen würde, wenn im Ergebnis keine Elemente größer als 100 sind, da takeWhile nicht weiß, wann es anhalten soll.

    
C. A. McCann 02.09.2011 18:03
quelle

Tags und Links