2017-09-26 9 views
8

私は現在、新しいAPIを構築していますし、それが現在提供機能の一つである:ブラケット機能のようにMonadUnliftIOまたはMonadMaskを使用しますか?

inSpan :: Tracer -> Text -> IO a -> IO a 

私は私より

inSpan :: MonadTracer m => Text -> m a -> m a 
などの署名を与え、モナドにその Tracerを移動するために探しています

inSpanの実装では、私は2つの主要なオプションを持っていることを意味している、bracketを使用しています。

class MonadUnliftIO m => MonadTracer m 

または

どのような方法をお勧めしますか?私が言及したすべてのタイプを制御しているので、IOを下部に適用していないので、MonadMaskに少し傾いていることに注意してください(つまり、おそらく純粋なMonadTracerインスタンスがある可能性があります)。

私は考慮すべきことがありますか?

答えて

19

はのは、最初のオプション(プロセスであなたの質問のいくつかを繰り返す)をレイアウトしてみましょう:

  • MonadMaskexceptionsライブラリから。これは広範囲のモナドと変圧器で動作することができ、基本モナドはIOである必要はありません。
  • MonadUnliftIOunliftio-core(またはunliftio)ライブラリー。このライブラリは、基底にIOのモナドでのみ機能し、何とかReaderT env IOと同型です。
  • MonadBaseControlmonad-controlライブラリーから。このライブラリはベースにIOが必要ですが、非ReaderTを許可します。

ここでのトレードオフ。 MonadUnliftIOは、最新のものであり、ライブラリの開発が最も進んでいません。これは、どのモナドがインスタンスになるかの制限に加えて、多くの良いインスタンスがまだ書かれていないことを意味します。

重要な質問は:MonadUnliftIOは、このように見えるのはなぜですか?ReaderTのようなものですか?これは、モナド状態の喪失に関する問題を防ぐためです。たとえば、bracket_ (put 1) (put 2) (put 3)のセマンティクスは実際には明確ではないため、MonadUnliftIOStateTインスタンスを許可しません。

MonadBaseControlは、ReaderT制限を緩和し、より広いライブラリサポートを備えています。それはまた、他の2つよりも内部的に複雑であると考えられますが、あなたの用法は本当に重要ではありません。そして、あなたは上記のようにモナド状態で間違いを犯すことができます。あなたの使い方を慎重にしていれば、これは重要ではありません。

MonadMaskは、完全に純粋なトランススタックを可能にします。純粋なスタックで非同期例外をモデリングすることの有用性については、良い議論があると思いますが、このようなアプローチは時々人がやりたいことです。より多くのインスタンスを取得する代わりに、モナド状態に関する制限と、timeoutまたはforkIOのような一部の制御アクション(IO)を持ち上げることができません。

私の推薦:あなたはほとんどの人は今日のことをやっている方法を一致させたい場合は

  • は、それが最もよく採用されたソリューションです、MonadMaskを選択するのが最善です。
  • でもの場合は、timeoutまたはwithMVarなどを入力する必要があります(MonadBaseControl)。
  • モナドの特定のセットがあることがわかっている場合は、モナドとの互換性が必要です。また、モナドの状態に対してコードの正確性をコンパイルするためには、MonadUnliftIOを使用してください。
関連する問題