7

IOアクションを永久に繰り返そうとしていますが、ある実行の結果を次の実行にフィードしています。このようなもの:

-- poorly named
iterateM :: Monad m => (a -> m a) -> a -> m b
iterateM f a = f a >>= iterateM f

Hoogleは私を助けてくれなかったようですが、私が望むものに魅力的に近いように見える関数がたくさんありますが、どれも正確に一緒になっていないようです。

4

4 に答える 4

4

iterateMまあ、私はコンビネータがこの型の署名を持っていることを期待します:

iterateM :: (Monad m) => (a -> m a) -> a -> m [a]

もちろん、ほとんどのモナドでは結果を抽出できなかったため、これはあまり便利なコンビネータではありません。コンビネータの基本的な命名基準に合わせるためのより賢明な名前は次のiterateM_とおりです。

iterateM_ :: (Monad m) => (a -> m a) -> a -> m b
iterateM_ f = fix $ \again x -> f x >>= again

このコンビネータは便利です。

countFrom :: (Enum a) => a -> IO b
countFrom = iterateM_ (\x -> succ x <$ print x)

ただし、簡単にするために、fix明示的な再帰を使用します。明示的に再帰的なコードは、それほど長くも読みにくくもなりません。

countFrom :: (Enum a) => a -> IO b
countFrom = fix (\again x -> print x >> again (succ x))
于 2012-05-29T15:08:25.543 に答える
4

そうです、この特定の種類のループが実装されている場所はわかりません。あなたの実装はうまく見えます。モナドループパッケージのパッチとして提出してみませんか?

于 2012-05-29T17:16:12.457 に答える
3

これが標準ライブラリに表示されないのは、決して終了しないからだと思います。反復関数はレイジーリストを利用しtakeて、結果リストの関数を使用して終了を指定できるようにします。ここでは、結果は単調であるため、これは不可能です。

明らかに、あなたのアイデアの精神は実行できます。少し違って見える必要があります:

iterateM :: Monad m => Int -> (a -> m a) -> a -> m a
iterateM 0 _ a = return a
iterateM n f a = f a >>= iterateM (n-1) f
于 2012-05-29T14:33:03.583 に答える
1

これは、実際にはforeverを使用するという観点から書くことができStateTます。

import Control.Monad.Trans.State
import Control.Monad.Trans.Class (lift)
import Control.Monad (forever)

iterateM :: Monad m => (a -> m a) -> a -> m b
iterateM f = evalStateT $ forever $ get >>= lift . f >>= put
于 2012-05-29T18:33:01.153 に答える