Sollte ich MonadUnliftIO oder MonadMask für ähnliche Funktionen bevorzugen?

8

Ich baue gerade eine neue API und eine der folgenden Funktionen ist:

%Vor%

Ich versuche, das Tracer in eine Monade zu verschieben und mir eine Signatur zu geben, die mehr wie

aussieht %Vor%

Die Implementierung von inSpan verwendet bracket , was bedeutet, dass ich zwei Hauptoptionen habe:

%Vor%

oder

%Vor%

Aber was sollte ich bevorzugen? Beachte, dass ich alle oben genannten Typen unter Kontrolle habe, was mich dazu bringt, mich etwas in Richtung MonadMask zu neigen, da es IO am Ende nicht erzwingt (das heißt, wir könnten vielleicht eine reine MonadTracer haben) Instanz).

Gibt es noch etwas, das ich beachten sollte?

    
ocharles 26.09.2017, 11:20
quelle

1 Antwort

19

Lassen Sie uns zuerst die Optionen festlegen (wiederholen Sie dabei einige Ihrer Fragen):

  • MonadMask aus der exceptions -Bibliothek. Dies kann bei einer Vielzahl von Monaden und Transformatoren funktionieren und erfordert nicht, dass die Basismonade IO ist.
  • MonadUnliftIO aus der unliftio-core (oder unliftio ) Bibliothek. Diese Bibliothek funktioniert nur für Monaden mit IO an ihrer Basis und die isomorph zu ReaderT env IO ist.
  • MonadBaseControl aus der monad-control -Bibliothek. Diese Bibliothek benötigt IO an der Basis, erlaubt aber nicht-ReaderT.

Jetzt die Kompromisse. MonadUnliftIO ist die neueste Ergänzung des Fray und hat die am wenigsten entwickelte Bibliotheksunterstützung. Dies bedeutet, dass zusätzlich zu den Beschränkungen, welche Monaden Instanzen sein können, viele gute Instanzen noch nicht geschrieben wurden.

Die wichtige Frage ist: Warum macht MonadUnliftIO diese scheinbar willkürliche Anforderung um ReaderT - ähnliche Dinge? Dies dient dazu, Probleme mit dem verlorenen monadischen Zustand zu verhindern. Zum Beispiel ist die Semantik von bracket_ (put 1) (put 2) (put 3) nicht wirklich klar und daher lässt MonadUnliftIO eine StateT -Instanz nicht zu.

MonadBaseControl lockert die Beschränkung ReaderT und bietet eine erweiterte Bibliotheksunterstützung. Es wird auch intern als komplizierter angesehen als die anderen beiden, aber für Ihre Verwendungen sollte das eigentlich keine Rolle spielen. Und es erlaubt Ihnen, Fehler mit dem oben erwähnten monadischen Zustand zu machen. Wenn Sie bei der Verwendung vorsichtig sind, spielt dies keine Rolle.

MonadMask ermöglicht völlig reine Transformatorstapel. Ich denke, es gibt ein gutes Argument, um die Nützlichkeit der Modellierung von asynchronen Ausnahmen in einem reinen Stack zu haben, aber ich verstehe, dass diese Art von Ansatz etwas ist, was Leute manchmal tun wollen. Im Gegenzug für das Erhalten von mehr Instanzen haben Sie immer noch die Einschränkungen in Bezug auf den monadischen Status und die Unfähigkeit, einige IO -Steueraktionen wie timeout oder forkIO zu erhöhen.

Meine Empfehlung:

  • Wenn Sie so arbeiten möchten, wie die meisten Leute heute Dinge tun, ist es wahrscheinlich am besten, MonadMask zu wählen, es ist die am besten angenommene Lösung.
  • Wenn Sie dieses Ziel möchten, aber müssen Sie auch timeout oder withMVar oder etwas tun, verwenden Sie MonadBaseControl .
  • Und wenn Sie wissen, dass es eine bestimmte Menge von Monaden gibt, mit denen Sie kompatibel sein müssen, und wollen Sie Zeitkompatibilitäten über die Korrektheit Ihres Codes gegenüber dem monadischen Zustand erstellen, verwenden Sie MonadUnliftIO .
Michael Snoyman 26.09.2017, 12:39
quelle

Tags und Links