(>>) :: (Monad m) => m a -> m b -> m b
最近 IO 周りが騒がしいので、鋭意モナドを勉強中です。
個人的に do 記法に馴染めないので、ここを見て脱糖を試みているのですが、どうも上手く動きません。
もともとはこんなコード。
関数 changed の中で、配列の読み込みをした後に書き込みをしています。返すのは書き込み前の値(False)。
import Control.Monad import Data.Array.IO main = print =<< changed =<< ini ini :: IO (IOArray Int Bool) ini = newArray (0, 0) False changed :: IOArray Int Bool -> IO Bool changed a = do b <- readArray a 0 when (not b) $ writeArray a 0 True return b
これを (>>) を使って書き換えると、書き込み後の値(True)が返ってしまいます。
どうやら b が2回実行されてしまうようです。
もともとのコードと等価にする(実行を1回に抑える)にはどうしたらよいのでしょうか?
changed :: IOArray Int Bool -> IO Bool changed a = (flip when (writeArray a 0 True) . not =<< mb) >> mb where mb = readArray a 0
[追記] そうか、 IO の世界に mb (readArray) が2回出てくるから駄目なんだ。こう書き換えれば上手くいく。
changed :: IOArray Int Bool -> IO Bool changed a = f =<< readArray a 0 where f b = when (not b) (writeArray a 0 True) >> return b