タイプが負の位置にあるMonadIO
ため、これをすべてのインスタンスで一般的に実行することはできません。特定のインスタンス(monad -control、 monad -peelIO
)に対してこれを行うハッキングに関するライブラリがいくつかありますが、特に例外や同様の奇妙なことをどのように処理するかに関して、それらが意味的に健全であるかどうかについていくつかの議論がありました。IO
編集:一部の人々は、ポジティブ/ネガティブな位置の区別に興味を持っているようです。実際、言うことはあまりありません(そして、おそらくすでに聞いたことがあるでしょうが、別の名前で)。用語はサブタイピングの世界から来ています。
サブタイピングの背後にある直感は、「代わりに、が期待されていた場所で使用できる場合の(これを記述します)a
のサブタイプです」ということです。多くの場合、サブタイピングの決定は簡単です。製品の場合、たとえば、これは非常に簡単なルールです。しかし、いくつかのトリッキーなケースがあります。たとえば、いつそれを決定する必要がありますか?b
a <= b
a
b
(a1, a2) <= (b1, b2)
a1 <= b1
a2 <= b2
a1 -> a2 <= b1 -> b2
さて、f :: a1 -> a2
タイプの関数を期待する関数とコンテキストがありますb1 -> b2
。したがって、コンテキストはf
の戻り値をあたかもそれであるかのように使用するb2
ので、それを要求する必要がありますa2 <= b2
。トリッキーなことは、コンテキストが。であるかのように使用する場合でも、コンテキストがを提供f
することです。したがって、私たちはそれを要求しなければなりません-それはあなたが推測するかもしれないものから後ろ向きに見えます!とは「共変」または「正の位置」で発生し、とは「反変」または「負の位置」で発生すると言います。b1
f
a1
b1 <= a1
a2
b2
a1
b1
(簡単に言うと、なぜ「ポジティブ」と「ネガティブ」なのですか?乗算によって動機付けられています。次の2つのタイプを検討してください。
f1 :: ((a1 -> b1) -> c1) -> (d1 -> e1)
f2 :: ((a2 -> b2) -> c2) -> (d2 -> e2)
f1
のタイプはいつのタイプのサブタイプである必要がありf2
ますか?私はこれらの事実を述べています(演習:上記のルールを使用してこれを確認してください):
- 持っている必要があり
e1 <= e2
ます。
- 持っている必要があり
d2 <= d1
ます。
- 持っている必要があり
c2 <= c1
ます。
- 持っている必要があり
b1 <= b2
ます。
- 持っている必要があり
a2 <= a1
ます。
e1
はで正の位置にありd1 -> e1
、これは次のタイプで正の位置にありf1
ます。さらに、全体e1
のタイプでポジティブな位置にありますf1
(上記の事実によると、共変であるため)。全期間におけるその位置は、各サブタームにおけるその位置の積です:正*正=正。同様に、d1
はで負の位置にありd1 -> e1
、これはタイプ全体で正の位置にあります。負*正=負であり、d
変数は確かに反変です。タイプでb1
は正の位置にあり、はでは負の位置にあり、タイプ全体では負の位置にあります。正*負*負=正、そしてそれは共変です。アイデアが浮かびます。)a1 -> b1
(a1 -> b1) -> c1
MonadIO
それでは、クラスを見てみましょう。
class Monad m => MonadIO m where
liftIO :: IO a -> m a
これは、サブタイピングの明示的な宣言と見なすことができます。具体的なIO a
のサブタイプにする方法を提供しています。すぐに、コンストラクターが正の位置にある場合は任意の値を取り、それらをsに変換できることがわかります。しかし、それだけです。負のコンストラクターをsに変換する方法はありません。そのためには、より興味深いクラスが必要です。m a
m
IO
m
IO
m