8

ノードと一意のキーの IntMap を使用してグラフ構造を作成したいと考えています。このトピックはここここでよく取り上げられています. 基本的に state -> (val,state) の関数を newtype でラップすることで状態モナドがどのように機能するかを理解しているので、そのモナドインスタンスを作成できます。私はそのトピックについてかなり読んだことがあります。プログラムの実行中に一意の(または単なる増分)値を取得する方法について、まだ頭を悩ませているようです。連続した ID の実行を取得するのは簡単ですが、モナドから抜け出すために "runState" を実行すると、現在の ID を追跡しなければならなかった場所に戻ったように思えます。モナドに閉じ込められたような気がします。私が検討したもう 1 つのオプションは、IntMap 全体と現在の「次の」ID を状態として保持することでしたが、それは非常に「必須」で極端に思えます。これ質問は非常に似ていますが、多くの回答が得られませんでした(または、明らかな何かが欠けているだけかもしれません)。プログラムの実行中に状態モナドを利用して一意の ID を取得する慣用的な方法は何ですか? ありがとう。

4

1 に答える 1

11

IOモナドを-化することを想像してみましょうState。それはどのように見えるでしょうか?私たちの純粋なStateモナドは、周りの単なるニュータイプです:

s -> (a, s)

まあ、IOバージョンは最終的な値を返す前に少し副作用をするかもしれません、それは次のようになります:

s -> IO (a, s)

そのパターンは非常に一般的で、名前があります。具体的にはStateT

newtype StateT s m a = StateT { runStateT :: s -> m (a, s) }

Tモナドトランスフォーマーであるため、名前の最後にaが付いていTます。m「ベースモナド」とStateT s m「変換された」モナドと呼びます。

StateT s mMonadの場合のみmですMonad

instance (Monad m) => Monad (StateT s m) where {- great exercise -}

ただし、それに加えて、すべてのモナド変換子MonadTransは次のように定義されたクラスを実装します。

class MonadTrans t where
    lift :: (Monad m) => m a -> t m a

instance MonadTrans (StateT s) where {- great exercise -}

の場合、のタイプtは次のことに特化しています。StateT slift

lift :: m a -> StateT s m a

つまり、ベースモナドのアクションを「持ち上げ」て、変換されたモナドのアクションにすることができます。

したがって、特定の問題については、追加の。StateT (IntMap k v) IOで拡張されるモナドが必要です。次に、このモナドでプログラム全体を記述できます。IOState

main = flip runStateT (initialState :: IntMap k v) $ do
    m <- get        -- retrieve the map
    lift $ print m  -- lift an IO action
    (k, v) <- lift readLn
    put (insert k v m)

とをまだ使用getしていることに注意してくださいput。これは、transformersパッケージが私が説明したすべての概念を実装し、次のように署名を一般化するgetためputです。

get :: (Monad m) => StateT s m s
put :: (Monad m) => s -> StateT s m ()

つまり、。内で自動的に機能しますStateTtransformers次に、次のように定義Stateします。

type State s = StateT s Identity

つまり、との両方にとを使用できるgetというputことStateですStateT

モナド変換子の詳細については、モナド変換子-ステップバイステップを強くお勧めします。

于 2013-01-25T16:11:28.000 に答える