15

で定義されたIOアクションを実行する場合someFun <$> (a :: IO ()) <$> (b :: IO ())aおよびbアクションの実行は順序付けられていますか?つまり、a以前に実行されたものを信頼できbますか?

GHCの場合、IOがStateを使用して実装されていることがわかります。またこれがApplicativeインスタンスであることがわかりますが、実際のインスタンス宣言のソースが見つかりません。Stateを通じて実装されるということは、さまざまなIO効果を連続させる必要があることを示唆していますが、それらの順序を定義する必要はありません。

GHCiで遊んでみると、Appliativeは効果の順序を保持しているように見えますが、それは普遍的な保証ですか、それともGHC固有ですか?詳細に興味があります。

import System.Time
import Control.Concurrent
import Data.Traversable
let prec (TOD a b) = b
fmap (map prec) (sequenceA $ replicate 5 (threadDelay 1000 >> getClockTime))

[641934000000,642934000000,643934000000,644934000000,645934000000]

ありがとう!

4

3 に答える 3

18

それは確かに決定論的です、はい。特定のインスタンスに対して常に同じことを行います。ただし、効果の順序として右から左よりも左から右を選択する固有の理由はありません。

ただし、次のドキュメントからApplicative

fもaの場合、 =および=Monadを満たす必要があります(これは、適用可能なファンクターの法則を満たしていることを意味します)。purereturn(<*>)appure<*>

の定義apはこれです、からControl.Monad

ap :: (Monad m) => m (a -> b) -> m a -> m b
ap =  liftM2 id

そしてliftM2、明白な方法で定義されています:

liftM2 f m1 m2 = do { x1 <- m1; x2 <- m2; return (f x1 x2) }

Monadこれが意味するのは、であると同時にであるすべてのファンクターについて、Applicative(これはコードで強制できないため、仕様により)Applicative左から右に機能することが期待されているためdoliftM2と同じことをしliftA2 f x y = f <$> x <*> yます。

上記の理由により、Applicative対応するがない場合でもMonad、慣例により、エフェクトは通常、左から右に並べられます。

より広義には、Applicative計算の構造は必然的に「効果」から独立しているため、通常、Applicative効果の順序付けとは無関係にプログラムの意味を分析できます。たとえば、のインスタンス[]が右から左のシーケンスに変更された場合、それを使用するコードは、リスト要素の順序が異なるだけで、同じ結果になります。

于 2013-01-10T13:49:50.590 に答える
4

はい、順序はモナドとアプリケーションの対応によって事前定義されています。これは簡単にわかります。コンビネータは、モナドの正常に動作するインスタンス(*>)のコンビネータに対応している必要があり、その定義は次のとおりです。(>>)Applicative

a *> b = liftA2 (const id) a b

つまり、b以前に実行された場合aApplicativeインスタンスは正常に動作しません。

編集:補足として:これはどこにも明示的に指定されていませんが、liftM2=liftA2などの他の多くの同様の対応を見つけることができます。

于 2013-01-10T14:00:37.193 に答える
2

IO Applicativeの場合、これは確かに当てはまります。ただし、非同期パッケージをチェックしてf <$> a <*> b、の効果abが並行して発生するApplicativeの例を確認してください。

于 2016-03-19T15:57:26.600 に答える