2012-03-06 9 views
8

内フォークする方法、Jいくつかのモナド変圧器スタックを検討モナド変換

{-# LANGUAGE GeneralizedNewtypeDeriving #-} 
... 
newtype J = J { runJ :: ErrorT Foo (StateT Bar IO) a } deriving (Applicative, Functor, etc) 

そして、いくつかの機能を言う:

peekNextQuux :: J Quux 
peekNextQuux = ... 

withJ :: J a -> IO (Either Foo a) 
withJ = ... 

その後、私はJコンテキスト内で自分自身を発見しました。私は今、私はJコンテキスト明らかに動作しません

g = withJ . liftIO . forkIO . forever $ peekNextQuux >>= liftIO . print 

内部の別のスレッド内でのぞくと、印刷quuxesたい

f = withJ $ peekNextQuux >>= liftIO . print 

を書くことができます。私は、このような単純な問題を解決する方法がいくつかありますが、それを理解することはできません。

答えて

8

どのように機能すると思いますか?別のスレッドは、JStateTErrorTをラップするため、何らかの状態と何らかのエラー処理にアクセスする必要があります。スレッドはこれにどのようにアクセスする必要がありますか?状態が新しいスレッドで更新されると、古いスレッドでもそれを変更する必要がありますか?新しいスレッドが例外をスローすると、古いスレッドは停止するはずですか?

StateTErrorTは純粋なモナド・トランスであるため、動作しません。したがって、私が記述した動作は実装できません。あなたが探しているよう

g = withJ . ... $ do 
    state <- get 
    liftIO . forkIO $ do 
    flip execStateT state . forever $ peekNextQuux >>= liftIO . print 
+0

ありがとうございました。 –

9

私はわからないんだけど、これは何が必要であれば、それが聞こえる:あなたは、明示的に新しいスレッドに状態を渡し、それを動作させるためにそこに新しい状態モナドを実行する必要がありますfunction

forkJ :: J() -> J ThreadId 

これはforkIOに似ていますが、代わりにJコンテキストで動作します。一般的にdflemstrのポイントはすべて有効です。ハスケルの純粋さに起因する国家管理についての未解決の疑問がたくさんあります。

しかし、あなたのロジックをちょっと再構成しようと思えば、あなたのために働く可能性のあるオプション(あなたが探しているのは、フォークを発行したときの元の状態にアクセスできる別のスレッドです) lifted-base pakcageです。これはモナドコントロールに依存します。基本的には、トランススタックの一番下にIOがある限り、上記のforkJ関数を提供します。

2つのスレッドをステートフルなやり方で通信させ、子で発生したエラーがErrorT機構の一部としてメインスレッドに伝播されるようにするには、これは不可能です(dflemstrの説明を参照)。ただし、Control.Concurrentモジュールファミリのコンストラクトを使用して、2つのスレッド間の通信チャネルを確立することはできます。次のモジュールの1つが必要なものを持っている可能性があります。

Control.Concurrent.Chan 
Control.Concurrent.MVar 
Control.Concurrent.STM 
+0

良い、私は '持ち上げベース'を見てみましょう。ありがとう。 –

関連する問題