3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Control.Monad.Trans】(2) StateTモナド

Last updated at Posted at 2020-01-03

Haskell/Monad transformers
A Gentle Introduction to Monad Transformers
モナドトランスフォーマー・ステップ・バイ・ステップ


【Control.Monad.Trans】(1) Identityモナド - Qiita
【Control.Monad.Trans】(2) StateTモナド - Qiita
【Control.Monad.Trans】(3) ExceptTモナド - Qiita
【Control.Monad.Trans】(4) ReaderTモナド - Qiita
【Control.Monad.Trans】(5) IOモナド - Qiita

Monad transformersを中心に、モナドの基本的な事項をまとめてみました。(1)~(5)までの連載で、Monad transformersを試行していきます。実際にはそれぞれの回で、Identity, StateT, ExceptT, ReaderT, IO モナドを積み重ねていく例題を示しています。

Monad transformersについては、以下のサイトが表向きは最新といわれるものでしょうが、中身はControl.Monad.Transの方をimportしたりしているので、説明の都合上、Control.Monad.Transを使います。
mtl - Hackage - Haskell

今回はStateTモナドです。

1. StateTモナドの定義

Control.Monad.Trans.State.Strict - Hackage - Haskell

m をbaseモナドとして、以下のようにStateT型を定義します。

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

モナドとしての定義です。baseモナド m のreturnや>>=を使って以下のように定義します。

instance (Monad m) => Monad (StateT s m) where
    return a = StateT $ \ s -> return (a, s)

    m >>= k  = StateT $ \ s -> do
        (a, s') <- runStateT m s
        runStateT (k a) s'

    fail str = StateT $ \ _ -> fail str

この定義からわかるように、m >>= k の m の値は a です。(*1)
failの定義の右辺のfailは、m=Identityの場合は、Identityモナドのfailです。

2. 補助関数 - state, get, put

StateTモナドは通常、グローバルな状態を管理するために使われます。アクセス関数としてgetとputが定義されます。stateは純粋な状態遷移関数をStateTモナドに変換するものです。

-- | Construct a state monad computation from a function.
-- (The inverse of 'runState'.)
state :: (Monad m)
      => (s -> (a, s))  -- ^pure state transformer
      -> StateT s m a   -- ^equivalent state-passing computation
state f = StateT (return . f)


-- | Fetch the current value of the state within the monad.
get :: (Monad m) => StateT s m s
get = state $ \ s -> (s, s)

-- | @'put' s@ sets the state within the monad to @s@.
put :: (Monad m) => s -> StateT s m ()
put s = state $ \ _ -> ((), s)

3. StateTモナドの使用例

簡単な例を2つ示します。その前に実行コマンドの簡略版を定義しておきます。

runState m = runIdentity . runStateT m

まずはgetとputの使用例です。

import Control.Monad.Trans.State.Strict
import Data.Functor.Identity

-- runState threeTicks 5

tick :: StateT Int Identity Int
tick = do n <- get
          put (n+1)
          return n

threeTicks :: StateT Int Identity Int
threeTicks = do n1<-tick
                n2<-tick
                n3<-tick
                return(n1+n2+n3)

以下のコマンドで実行します

*Main> runState threeTicks 5
(18,8)

次はStateTでスタックを実現します。stateを明示的に使う例となっています。

Control.Monad.Trans.State.Strict
import Data.Functor.Identity

-- runState tasu [8,7..0]

type Stack = [Int]

tasu :: StateT Stack Identity Int
tasu = do
  state $ \xs -> ((), 9:xs)       -- push 9
  a <- state $ \(x:xs) -> (x, xs) -- a <- pop
  b <- state $ \(x:xs) -> (x, xs) -- b <- pop
  return (a+b) 

ここで注目して欲しいのは、StateTモナドの値である a と b は、それぞれ \(x:xs) -> (x, xs) の x の値であることです。このことは上で述べた(*1)に対応しています。

それでは実行してみましょう。

*Main> runState tasu [8,7..0]
(17,[7,6,5,4,3,2,1,0])

今回は以上となります。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?