内容はStateモナドの詳細を隠すためのコードの書き方が掲載されています、そのまま直書きですとこんな感じ、
module Supply ( Supply , next , runSupply ) where import Control.Monad.State newtype Supply s a = S (State [s] a) unwrapS :: Supply s a -> State [s] a unwrapS (S s) = s instance Monad (Supply s) where s >>= m = S (unwrapS s >>= unwrapS . m) return = S . return runSupply :: Supply s a -> [s] -> (a, [s]) runSupply (S m) xs = runState m xs next :: Supply s (Maybe s) next = S $ get >>= \st -> case st of [] -> return Nothing (x:xs) -> put xs >>= \_ -> return (Just x)サンプルはnext関数を呼ぶとStateモナドが持っている状態のリストから1つづつ値を返してくるというコード、こうやってSupplyモナドを走らせる
*Supply> runSupply next [1,2,3,4,5] (Just 1,[2,3,4,5])これはこれでいいのですが、ghc-7.8.3で実行するとこんなエラーがでる
GHCi, version 7.8.3: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Prelude> :load "/home/cuomo/Code/haskell/State/Supply5.hs" [1 of 1] Compiling Supply ( /home/cuomo/Code/haskell/State/Supply5.hs, interpreted ) /home/cuomo/Code/haskell/State/Supply5.hs:15:10: Warning: ‘Supply’ is an instance of Monad but not Applicative - this will become an error in GHC 7.10, under the Applicative-Monad Proposal. Ok, modules loaded: Supply. *Supply>「ghc-7.10だとエラーになるからSupplyのApplicativeインスタンスを書けよ」って脅かされる、なので自分でインスタンスを適当に書いてみた
... import Control.Applicative ... instance Applicative (Supply s) where pure = return (S mf) <*> (S m) = undefinedそしたら今度は「Functor書け」って怒られる始末、なのでいわれるがままにFunctorを書く
instance Functor (Supply s) where fmap f (S m) = undefinedこれで、構文チェックはOKらしいが「undefined」なので詳細をつめる
instance Functor (Supply s) where fmap f (S m) = S $ f <$> m instance Applicative (Supply s) where pure = return (S mf) <*> (S m) = S $ mf >>= \f -> f <$> mこれで警告やエラーはとまったがFuntor則にあってるかどうか確かめないとわからないので、確認してみる
第1法則「fmap id = id」の確認
*Supply> runSupply (id `fmap` next) [1,2,3,4,5] == runSupply next [1,2,3,4,5] True良さげ...
第2法則「fmap (f . g) = fmap f . fmap g」の確認
*Supply> :m +Data.Maybe *Supply Data.Maybe> runSupply (fmap (id . fromJust) next) [1,2,3,4,5] == runSupply ((fmap id . fmap fromJust) next) [1,2,3,4,5] Trueという感じでいいのでしょうか?
next関数がMaybe値を返してくるのでfromMaybeを使って試してみました
そうするとこんな感じで使えるApplicativeだと
*Supply> runSupply (return (liftM (+1)) <*> next) [1,2,3,4,5] (Just 2,[2,3,4,5])何となくしっくり来た感があるのですが間違っていないでしょうか...ちなみに「アル中ハイマー」と「アルチュハイマー」は別物です、どちらかといえば「アルチュハイマー」の方がかわいいです。
アルチュハイマーな型はこちらをどうぞ
0 件のコメント:
コメントを投稿