私はそのようなコードを持っています:
foldl (\a x -> a ++ (f x)) [] list
すべて問題ないようですが(f x) :: IO [String]、(++)エラーが発生します ([文字列] != IO [文字列])。
空の IO[String] リストを定義するには? クリーン(fx)が作れません。
ここで必要なコンビネータはおそらく
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]
の:
foldl (\a x -> a ++ (f x)) [] list
あなたはやろうとしていますa ++ f xがf 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 回実行dしcます。であり、このリスト操作にははるかに適しています。baconcatfoldr
次のものがあるとします。
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。