16

次の例を検討してください。

safeMapM f xs = safeMapM' xs []
    where safeMapM' []     acc = return $ reverse acc
          safeMapM' (x:xs) acc = do y <- f x
                                    safeMapM' xs (y:acc)

mapM return largelist      -- Causes stack space overflow on large lists
safeMapM return largelist  -- Seems to work fine

mapM大きなリストでを使用すると、safeMapM正常に動作しているように見えますが、スタック スペース オーバーフローが発生します (GHC 7.6.1 を と共に使用-O2)。safeMapMしかし、Haskell の標準ライブラリに似たような関数を見つけることができませんでした。

mapM(またはその点で)使用することはまだ良い習慣と考えられていsequenceますか?
もしそうなら、スタックスペースオーバーフローの危険があるにもかかわらず、なぜそれが良い習慣であると考えられているのですか?
そうでない場合、どの代替案を使用することをお勧めしますか?

4

3 に答える 3

9

Niklas B. のように、 のセマンティクスは効果的mapMな右折りのセマンティクスであり、反転したバージョンよりも多くの場合で正常に終了します。一般に、mapMデータの膨大なリストに対して結果を生成するマップを作成することはほとんどないため、より理にかなっています。より一般的には、そのようなリストの効果を評価する必要があり、その場合mapM_sequence_結果を破棄する と が通常推奨されます。

編集: つまり、質問で提起された問題にもかかわらず、yes、一般的に使用され、通常は良い習慣と見なされますmapMsequence

于 2013-03-21T17:09:11.823 に答える
7

もしそうなら、スタックスペースオーバーフローの危険があるにもかかわらず、なぜそれが良い習慣であると考えられているのですか? そうでない場合、どの代替案を使用することをお勧めしますか?

生成されたリスト要素を処理する場合は、pipesまたはを使用しますconduit。どちらも中間リストを構築することはありません。

pipesそれが私のライブラリなので、私は道を示します。IO最初に、ユーザー入力からモナドで生成された数の無限リストから始めます。

import Control.Proxy

infiniteInts :: (Proxy p) => () -> Producer p Int IO r
infiniteInts () = runIdentityP $ forever $ do
    n <- lift readLn
    respond n

今、それらが生成されたときにそれらを印刷したいと思います。これには、ダウンストリーム ハンドラーを定義する必要があります。

printer :: (Proxy p) => () -> Consumer p Int IO r
printer () = runIdentityP $ forever $ do
    n <- request ()
    lift $ print n

これで、 と を使用して接続し、ProducerConsumer使用し(>->)て結果を実行できrunProxyます。

>>> runProxy $ infiniteInts >-> printer
4<Enter>
4
7<Enter>
7
...

次に、ユーザーから s を読み取りInt、メモリに複数の要素を保存することなく、それらが生成されたときにそれらをコンソールにエコーバックします。

したがって、通常、要素のストリームを生成してすぐに消費する効果的な計算が必要な場合は、mapM. 適切なストリーミング ライブラリを使用します。

について詳しく知りたい場合は、チュートリアルを読むことpipesをお勧めします。

于 2013-03-21T18:00:28.663 に答える
-1

怠惰なキャンプにとどまりたい場合は、lazyioパッケージを使用すると、入力リストを遅延処理できます。それ以外の

mapM f

あなたが書く

import qualified System.IO.Lazy as LazyIO

LazyIO.run . mapM (LazyIO.interleave . f)

もうスタックオーバーフローはありません。

于 2016-12-14T20:55:46.010 に答える