2012-12-07 6 views
10

Als shown in this answer, seq kombiniert mit undefined macht sehr seltsame Dinge, wenn es um Gleichsetzung geht, zum Beispiel kann es jede Monade zum Scheitern bringen. Ein anderes Beispiel ist in this question.Ist `evaluate` sicher im Vergleich zu` seq`?

Kürzlich stolperte ich über evaluate :: a -> IO a, die eine ähnliche Sache tut - es wertet sein Argument zu WHNF aber nur aus, wenn die IO Aktion ausgewertet wird. Dies scheint viel sicherer zu sein, da man erwartet, dass wir "in IO alles machen können". Natürlich kann es nicht überall verwendet werden, aber oft ist die Notwendigkeit, einen Ausdruck auszuwerten, irgendwie mit einer IO Operation verbunden (wie man einen produzierenden Thread zwingt, eine Berechnung anstelle eines konsumierenden Threads zu bewerten, wenn man mit MVar arbeitet).

Also ich möchte fragen, wie sicher ist evaluate? Ist es möglich, Beispiele zu erstellen (beinhalten IO natürlich), wo es die Argumentation über Code wie seq bricht? Oder kann ich es als einen sicheren Ersatz für seq betrachten (wenn es für ein bestimmtes Programm möglich ist)?

Antwort

5

Nein, Sie erhalten immer noch die gleichen Probleme, die durch den Befehl seq verursacht werden, in dem jede Monade, die im ersten Argument von evaluate verwendet wird, ihre Monadenregeln gebrochen hat. es von der Regel in ertes Antwort Gründend:

In der Kleisli Kategorie der Monade Aufstieg zu return gibt, ist die Identität morphism und (<=<) ist Zusammensetzung. So return muss eine Identität für (<=<) sein:

return <=< x = x 

Dies bedeutet, sollten Sie in der Lage sein, zu ersetzen return <=< x mit x mit jedem gültigen Monade, ohne den Betrieb des Programms zu ändern.

verwenden, die mit der Funktion evaluate ...

evaluate (return <=< undefined :: a -> Identity b) >> putStrLn "hello" 

Ausgänge Hallo. was mit Hilfe sollte durch Ersetzen return <=< undefined mit undefined eine äquivalente Aussage sein:

evaluate (undefined :: a -> Identity b) >> putStrLn "hello" 

stattdessen verursacht eine Prelude.undefined Ausnahme.

Dies geschieht nur mit der Funktion evaluate. Beachten Sie, dass return genau die gleiche Signatur wie evaluate hat. Wenn Sie in den obigen Befehlen evaluate durch return ersetzen, ist die resultierende Aktion für beide Befehle dieselbe (sie geben hello aus).