それは、正しい折り方がどのように機能するかによるものです。フォールド関数は累積です。各ステップで、1 つの要素 (この場合はキーと値) と残りのデータの累積結果が与えられると、それらを 1 つの結果に結合します。折り畳みは全体としてそれを再帰的に行い、データのセット全体を要約します。
あなたの場合、アキュムレータ関数の「結果」入力を破棄していますb
。引数は決して使用されないことに注意してください。IO a
は、余分なジャンクが付加された単なる type の値ではなく、実際a
に表すのは を生成する計算a
であり、その計算は、の最終値の一部として他の計算と組み合わせることによってのみ実行されることに注意してください。main
関数 (または、GHCi では、評価される式の)。
蓄積された値を破棄することにより、他の計算が最終結果の一部になることはなく、したがって値が出力されることはありません。
あなたの質問の言い方から、あなたは Haskell の関数型スタイルよりも命令型スタイルのプログラミングに慣れていると思います。明らかに、折り畳みの間に意味のある意味で印刷が実際に「起こっている」命令型言語では、累積された値は役に立たないと仮定するのが合理的です。それが役立つ場合は、これを一種のメタプログラミングと考えてください。値を出力するループを実際に書いているのではなく、実際の出力を行う命令型プログラムを作成していて、累積された値を破棄することで、展開されたループの最初の行以外を基本的にすべて破棄して、類推が悪い。
いずれにせよ、この場合におそらく必要なのは、「残りのデータを出力する」アクションであるb
パラメーターを取り、それをアクションと結合することputStrLn ...
です。これは(>>)
、基本的に「最初のアクションを実行し、結果を無視する」ことを意味する演算子です。 、2番目を実行します」。これは、命令型スタイルの「ループ内の print ステートメント」をかなり直接的に翻訳したものです。
また、それがまったく的外れであることは理解していますが、フォーマットと印刷をそのように混在させることはおそらく避けたいと思います。私の目には、各キーと値のペアを個別にリストにフォーマットしてから、その上でフォーマットする方が整然としているように見えますmapM_ putStrLn
。
mapM_
ここで行っていることの本質を説明する高階関数です。あるタイプのリストと、 を何らかのアクションに変換するa
関数が与えられると、関数を各アイテムに適用し、アクションの結果リストを順番に実行します。の typeは一見不可解に見えますが、Haskell の優れた点の 1 つは、型シグネチャの読み取りに慣れると、の型が一目で理解できるだけでなく、実用的なものが 1 つしかないという点でほぼ自己文書化できることです。そのタイプの関数が行うことであり、それはまさにそれ自体が行うことです。a
IO
mapM_
Monad m => (a -> m b) -> [a] -> m ()
mapM_
mapM_