5

私はそのようなコードを持っています:

foldl (\a x -> a ++ (f x)) [] list

すべて問題ないようですが(f x) :: IO [String](++)エラーが発生します ([文字列] != IO [文字列])。

空の IO[String] リストを定義するには? クリーン(fx)が作れません。

4

3 に答える 3

15

ここで必要なコンビネータはおそらく

Prelude Control.Monad> :t foldM
foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a

そしてそれで

foldM (\a x -> fmap (a++) (f x)) [] list

アクションを順番に実行し、それらが生成するf xを蓄積します。[String]

于 2013-01-15T21:44:19.350 に答える
4

の:

foldl (\a x -> a ++ (f x)) [] list

あなたはやろうとしていますa ++ f xf x :: IO [String]、それはうまくいきません。何が起こっているのかを理解できるか見てみましょう。

xfor はあなたのから来ることを意味するので、リストの各要素に順番にlist適用し、それぞれが を与え、進むにつれてそれらを連結したいと考えます。f[String]

mapM :: Monad m => (a -> m b) -> [a] -> m [b]関数をリストにマップし、モナド操作を 1 つにまとめて、出力をリストに結合する を使用します。

concatMapM :: (a -> IO [String]) -> [a] -> IO [String]
concatMapM f list = fmap concat (mapM f list)

ここではfmap、純粋な関数concatを IO 操作の結果に適用していました。

を使用してテストできます

fileLines :: FilePath -> IO [String]
fileLines filename = fmap lines (readFile filename)

*Main> concatMapM fileLines ["test1.txt","test2.txt"]
["This is test1.txt","It has two lines.","This is test2.txt","It has two lines too."]

concatこの方法は、 よりも効率的に機能するため、foldl を試みるよりも優れていfoldl (++)ます。これを自分で確認するには、これらの速度を比較してください。

*Main> writeFile "test3.txt" $ foldl (++) [] (map show [1..10000])
*Main> writeFile "test3.txt" $ foldr (++) [] (map show [1..10000])

問題は、リストを4 回foldl実行することです。最初に追加するときに実行し、次に実行し、次に追加し、次に実行し、追加すると、4 つすべてを実行します。追加します。これは労力の大きな無駄です。(((a++b)++c)++d)++eababcabcde

foldrそうすることで、各リストをa ++ (b ++ (c ++ (d ++ e)))1 回実行dcます。であり、このリスト操作にははるかに適しています。baconcatfoldr

于 2013-01-16T03:14:47.983 に答える
1

次のものがあるとします。

list :: [a]
f :: a -> IO b

type の最終値を取得したいとしますIO [b]。をマッピングfするlistと、 type のリストが得られます[IO b]sequence :: Monad m => [m a] -> m [a]次のように使用して、内側から外側に「IOを移動」できます。

sequence (map f list) :: IO [b]

このように考えてみてください: 順序付けの前に、 type の値を作成するための命令のリストがありましたb。これで、 のリストを作成する命令が 1 つできましたb

于 2013-01-15T21:53:01.650 に答える