Stateモナドが(なんとなく)わかった

Stateモナドがわからない。ということで「入門Haskell」にのっていたBase64エンコードソースコードを写経。
そしたらなんとなくわかってきた。

procChar :: Int -> State B64EncState String
procChar c = get >>= transit
    where
      transit First      = do put $ Second (c .&. 3)
                              return [table !! shiftR c 2]
      transit (Second n) = do put $ Third (c .&. 15))
                              return [table !! (shiftL n 4 .|. shiftR c 4)]
      transit (Third n)  = do put First
                              return [table !! (shiftL n 2 .|. shiftR c 6), table !! (c .&. 63)]

写経した当初は、「まずgetで状態を取得して」というのがピンとこず。
式のどこにも状態がないじゃん。getで取得する状態ってどこにあるのよ?と。
が、Stateが

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

ということを思いだすとようやくピンときた。
Stateというのはデータではなく、関数だ。
上記のprocCharは「State B64EncState String」型を返すということは、データを返しているわけではなく、関数を返しているのだな。
で、

b64Enc s = do strs <- mapM (procChar . ord ) s
              suffix <- gets calcSuffix
              return (concat strs ++ suffix)

として作った「b64Enc s」も「State B64EncState String」型を返す。
そして、

base64Encode s = evalState (b64Enc s) First

とevalStateをかますことで実際の計算がなされると。このときにやっとgetで取得される状態が渡される。
関数型言語において、関数はファーストクラスオブジェクトである」という言葉を知ってはいたが、きっちりと実感、理解できていなかったからだろう。「State s a」というのが関数にみえてなかった。関数であると理解したら、なんとなくStateモナドがわかった気がする。

よし、わかった気がするでとめるのはもったいないので、Stateモナドを使って何か書こう。さて、何書こう。