2012-09-02 22 views
5
class Monad m => MonadState s m | m -> s where 
    -- | Return the state from the internals of the monad. 
    get :: m s 
    get = state (\s -> (s, s)) 

    -- | Replace the state inside the monad. 
    put :: s -> m() 
    put s = state (\_ -> ((), s)) 

    -- | Embed a simple state action into the monad. 
    state :: (s -> (a, s)) -> m a 
    state f = do 
     s <- get 
     let ~(a, s') = f s 
     put s' 
     return a 

instance MonadState s m => MonadState s (MaybeT m) where... 

なぜMonadStateのインスタンスには状態とモナドが必要なのですか?なぜ、単一のパラメータStateクラスを作成しないのですか?MonadStateでMultiParamTypeClassesを使用する理由

+4

私があなたが提案している代替品を理解しているかどうかはわかりません。 'state ::(s - >(a、s)) - > m a'の型を' m'と 's'の両方で書くことはどうですか? – Owen

+0

'class MonadState s where ...'から始め、sをモナドに入れずに 'get :: s'と' put :: s - >() 'を実行するとします。私たちがMaybe状態かEither状態かIO状態かどうかを気にする必要のない、より単純な状態実装を実現できますか? –

答えて

6

Gertの質問に答えてもらいましょう。それはかなり異なる質問ですから。

疑問は、なぜ私たちは

class State s where 
    get :: s 
    put :: s ->() 

まあ、我々はこれを書くことができるを書き込むことはできませんされています。しかし、今問題は、私たちはそれで何ができるのでしょうか?難しいのは、コードがput xで、その後にgetである場合、getputにリンクするにはどうすればよいのでしょうか?

問題は、タイプが()sの場合のみ、リンクする方法がないことです。さまざまな方法で実装することはできますが、機能しません。 putからgetにデータを運ぶ方法はありません(誰かがこれをよりよく説明できるかもしれませんが、理解するための最善の方法はデータを書き込むことです)。

モナドは必ずしも操作がリンク可能にする唯一の方法ではありませんが、それは二つの文を一緒にリンクする>>オペレータを持っているので、それは、方法です:

(>>) :: m a -> m b -> m b 

ので、我々は

(put x) >> get 
を書くことができます

EDIT:ここthe StateT instance defined in the package

012を用いた例であります
+0

答えにIOの例を追加できますか? '(put x)>> get >> =(\ x - > print x)'なんか? –

+1

@GertCuykens私は 'IO'でそれをどうやって行うのか考えることはできません。 'IO'は' State'のように状態を置く場所がありません。しかし、私は 'IO'の周りに' StateT'を使って例を追加することができます。 – Owen

+0

@Owen - 'IORef'を使って' IO'だけを使って例を作ることができます。 –

4

状態の種類をモナドの種類に関連付ける方法が必要です。 とFunctionalDependenciesは片道です。ただし、TypeFamiliesを使用して行うこともできます。

class (Monad m) => MonadState m where 
    type StateType m 

    -- | Return the state from the internals of the monad. 
    get :: m (StateType m) 
    get = state (\s -> (s, s)) 

    -- | Replace the state inside the monad. 
    put :: StateType m -> m() 
    put s = state (\_ -> ((), s)) 

    -- | Embed a simple state action into the monad. 
    state :: (StateType m -> (a, StateType m)) -> m a 
    state f = do 
     s <- get 
     let ~(a, s') = f s 
     put s' 
     return a 

instance MonadState m => MonadState (MaybeT m) where 
    type StateType (MaybeT m) = StateType m 

    ... 

これはmonads-tf packageのアプローチです。

+1

注: 'monads-tf'は基本的に廃止されました。もともと、Rossは 'mtl'をHaskell 98の' transformers 'に分割し、 'monads-tf'と' monads-fd'の2つのパッケージを選びました。しかし、 'mtl'、' monads-tf'と 'monads-fd'はすべて同じモジュール名を使用していたので、コミュニティを3つの方法で分割すると、これはひどいものでした。修正は、古い 'mtl'を廃止し、' monads-fd'を 'mtl'にして、' monads-tf'を死に至らせることでした。私は 'monads-tf'から別のモジュール名を使用していたクラスには反対しませんが、それはまったく有害です。 –