2011-11-18 手続き的な彼女 〜 procedural language
do 式中の無名再帰でループを回す
do 式の中でループを書く場合,イチイチ let を使うのは面倒だなぁ,
と常々考えていたのですが,よく考えたら これ, fix を使えば済む話ですね:
import Data.IORef import Data.Function main = do -- 無引数無名再帰 a_ref <- newIORef ( 0 :: Int ) fix $ \loop -> do a <- readIORef a_ref if a < 10 then do print a writeIORef a_ref (a+1) loop else return () -- 引数付き無名再帰 sum <- newIORef ( 0 :: Int ) ( `fix` 0 ) $ \ loop i -> do if i < 10 then do modifyIORef sum(+ i) loop $ i + 1 else return () print =<< readIORef sum
IORef と組み合わせれば かなり手続き的に書けて,個人的に大満足です.
まぁ,継続モナドを使う方が楽なケースも多いですが.
あ,継続モナドに関しての詳しい解説は, Haskell Advent Calendar 2011 の僕の番の時にでも.
追記
当たり前ですが,今回のような例では
main = do forM_ [0..9] $ \i -> do print i print $ sum [0..9]
と書けば それで済む話ですし,そう書いた方がエレガントです.
ただ,実際のプログラミングでは,そうではないケースも多いわけで,
継続モナドで forever を使ったりするのは,何か違うんじゃね? と.
そもそも Haskell の Control.Monad には,手続き言語で言う while 系列の
「途中で処理を中止する」関数が存在しないんですよね.
仕方ないので
takeWhileM_ :: Monad m => ( a -> m Bool ) -> [a] -> m () takeWhileM_ p = ( `foldr` return () ) $ \x action -> do cond <- p x if cond then action else return () main = do (`takeWhileM_` [1..] ) $ \i -> do if i < 10 then do print i return True else return False
的な関数を用意してみても,どうも読みやすいようには書けない*1.
仕方ないので継続モナドを使うことも考えましたが,それはそれで liftIO がキモい.
どうしたもんかな,と思って,色々と試行錯誤した結果,
(\f -> foldr f (return ()) [1..] ) $ \_ action -> do いろいろと束縛 if 条件 then do 処理 action else return ()
的なコードに至り,その後,あれ,これって無名再帰と似てね? と思い至った次第.
*1: return True とかが邪魔になるので
トラックバック - http://d.hatena.ne.jp/gintenlabo/20111118/1321632864
リンク元
- 32 http://t.co/41itMTnk
- 6 http://reader.livedoor.com/reader/
- 5 http://d.hatena.ne.jp/
- 5 http://k.hatena.ne.jp/keywordblog/Haskell
- 5 http://www.google.co.jp/url?sa=t&rct=j&q=iso/iec 14882:2011&source=web&cd=2&ved=0CDUQFjAB&url=http://d.hatena.ne.jp/gintenlabo/20110903/1315059927&ei=ShLJTrTOCIHJmQWHq_Un&usg=AFQjCNEQaBv5yTS_ak_d02AagzlYjsJy9Q&sig2=Hn0IrliUfPSVSBIVifn0RQ
- 4 http://d.hatena.ne.jp/keyword/Haskell
- 4 http://pipes.yahoo.com/pipes/pipe.info?_id=02db597254ec68550537866a2fca2ce6
- 4 http://www.google.com/reader/view/feed/http://blog.livedoor.jp/mikako0607jp/index.rdf
- 2 http://a.hatena.ne.jp/uskz/?gid=290138
- 2 http://atnd.org/events/10573
