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の定義で関数部分が状態を変化させないことから,すぐに示すことができます.