Stateモナドを考える(その2)

分からないときは定義をみるのはお約束.ということでControl.Monad.Stateをみます.

module Control.Monad.State (
  module Control.Monad.State.Lazy
  ) where

import Control.Monad.State.Lazy

はうっ・・別の呼んでますね.本体はControl.Monad.State.Lazyであって,これがエクスポートしてるものは全部エクスポートしてるということは,どこかで名前(置き場所(階層))が変わったんでしょうね,きっと.

ということで本体はControl.Monad.State.Lazyです.この中にはStateTモナドもいますが,今回はパスです.

module Control.Monad.State.Lazy (
    module Control.Monad.State.Class,
    -- * The State Monad
    State(..),
    evalState,
    execState,
    mapState,
    withState,
    -- * The StateT Monad
(中略)
    module Control.Monad,
    module Control.Monad.Fix,
    module Control.Monad.Trans,
    -- * Examples
    -- $examples
  ) where

import Control.Monad               -- ここからexportされたのもexportされる
import Control.Monad.Cont.Class
import Control.Monad.Error.Class
import Control.Monad.Fix           -- ここからexportされたのもexportされる
import Control.Monad.Reader.Class
import Control.Monad.State.Class   -- ここからexportされたのもexportされる
import Control.Monad.Trans         -- ここからexportされたのもexportされる
import Control.Monad.Writer.Class

Stateモナド(というか,とりあえずはState型というべき?)の定義は

newtype State s a = State { runState :: s -> (a, s) }

であって(Control.Monad.State.Lazyより),データコンストラクタStateがくっついた関数であって,その関数にフィールドラベルrunStateが付いています.sが「状態」の型であって,「a」が計算結果の型です.State s aは「State印つきの関数」です.

StateはFuntor

StateはFunctor,平たくいえばmap(fmap)があるということです.数学でいう関手(Functor)のうちの「共変関手」の性質(射の合成の順序を保存する,恒等射は恒等射に移す)をもつものを定義できることを意味します.Functorクラスの定義も併記しておきます.

-- Functorクラスの定義
class  Functor f  where
    fmap        :: (a -> b) -> f a -> f b

-- State sがFunctorクラスのインスタンスであること
instance Functor (State s) where
    fmap g m = State $ \s -> let (a, s') = runState m s
                             in (g a, s')

-- fmapがみたさなければいけない性質
-- fmap id  ==  id 
-- fmap (f . g)  ==  fmap f . fmap g

これはそのまま納得できます.お約束のようなものですが,正確にはState sがFunctorクラスのインスタンスであることが注意.fmapの性質もid a = aであることと,fmapの定義で関数部分が状態を変化させないことから,すぐに示すことができます.