10

いくつかのモナド変換子スタックを考えてみましょう。

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

そして のいくつかの機能J:

peekNextQuux :: J Quux
peekNextQuux = ...

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

それから私はJ文脈の中にいることに気づきました。私は書くことができます

f = withJ $ peekNextQuux >>= liftIO . print

J今、コンテキスト内の別のスレッド内で quxes を覗いて印刷したい

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

これは明らかに機能しません。このような単純な問題を解決する方法がいくつかあると思いますが、それを理解することはできません。

4

2 に答える 2

10

これが必要かどうかはわかりませんが、関数を探しているようです

forkJ :: J () -> J ThreadId

これは forkIO に似ていますが、代わりに J コンテキストで動作します。一般的に言えば、dflemstr のポイントはすべて有効です。Haskell の純粋性により、状態管理に関する多くの未解決の問題があります。

ただし、ロジックを少し再構築したい場合は、(フォークを発行したときの元の状態にアクセスできる別のスレッドだけを探している場合) うまくいく可能性のあるオプションの 1 つがLifted- です。モナド制御に依存する基本パッケージ。Transformer スタックの一番下に IO がある限り、基本的に上記の forkJ 関数を提供します。

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

Control.Concurrent.Chan
Control.Concurrent.MVar
Control.Concurrent.STM
于 2012-03-06T16:57:33.567 に答える
9

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

とは純粋なモナド トランスフォーマーであるため、動作しません。したがって、説明した動作を実装することはできませんStateTErrorT状態を明示的に新しいスレッドに渡し、そこで新しい状態モナドを実行して動作させる必要があります。

g = withJ . ... $ do
  state <- get
  liftIO . forkIO $ do
    flip execStateT state . forever $ peekNextQuux >>= liftIO . print
于 2012-03-06T14:25:16.897 に答える