2012-04-04 9 views
9

は、ランダムな数字をプリントアウトすることになっている次のコードを考えてみましょう。関数 'randoms'が無限のリストを生成するので、それは驚くべきことではありません。 xsの最初の10個の値だけを出力したいとします。どうすればいい? xsは型IO [Double]を持ち、[IO Double]型の変数が必要だと思います。 2つの間で変換する演算子は何か。Haskellのモナド:実行すると、私はセグメンテーションフォールトエラーを取得</p> <pre><code>import System.Random.Mersenne main = do g <- (newMTGen Nothing) xs <- (randoms g) :: IO [Double] mapM_ print xs </code></pre> <p>:へ[ダブル] IOは、[IOダブル]

+0

を、IO [ダブル] - > [IOダブル]基本的に '配列' のリバースタイプの署名です。 – Gautam

+3

ここではセグメンテーションがありません。 –

+1

何らかの種類の不具合やハードウェアの問題などのように聞こえる場合は、[memtest86 +](http://www.memtest.org/)のチェックを実行するとよいでしょう。 – ehird

答えて

11

セグメンテーションフォールトエラーが発生し、FFIまたはその名前にunsafeの機能を使用しなかった場合、ではないはどんな状況でも驚くほどです!これは、GHC、またはあなたが使用しているライブラリが何か安全でないことをしているバグがあることを意味します。

Doubleの無限リストをmapM_ printで印刷すると問題はありません。リストは段階的に処理され、プログラムは一定のメモリ使用量で実行されます。あなたが使用しているSystem.Random.Mersenneモジュールにバグがあるか、それがベースとしているCライブラリのバグか、コンピュータに問題がある(RAMの欠陥など)疑いがあります。 newMTGenは、この警告が付属していることを注:

は、電流SFMTライブラリが大幅に不純であることに、現在、唯一の発電機は、プログラムごとの許可されています。それを再初期化しようとすると失敗します。

提供されているglobal MTGenを使用する方がよい場合があります。

つまり、IO [Double][IO Double]に変換することはできません。 IOアクションを実行しなくても結果リストがどれくらい長く続くかを知る方法はありません。これは、あなたが純粋な結果を持っているためです(IOアクションを含むものの)。無限リストについては、次のように書くことができます:

desequence :: IO [a] -> [IO a] 
desequence = desequence' 0 
    where 
    desequence n m = fmap (!! n) m : desequence (n+1) m 

しかし、あなたはこのリスト内のアクションを実行するたびに、IO [a]アクションが再び実行されるだろうし。残りのリストを破棄してしまいます。

理由randomsは、unsafeInterleaveIOの遅延IOを使用しているため、無限の乱数のリストを返すことができます。

その他、可能性が低い可能性、Cライブラリのmiscompilationを含める(名前に「安全でない」にも関わらず、この1 ことはできません原因セグメンテーション違反なので、他の何かが進行中であるが、ことに注意してください) GHCのバグなどがあります。

+3

記録のために、質問者のコンピュータでは何かが間違っている可能性があると思います。提供されたコードは私のためにセグメンテーションされません。 –

+3

+1「IO [Double]」を「[IO Double]」に変換することはできません... IOアクション「 –

+0

」を実行せずに結果リストがどれくらい長くなるかを知る方法はありません最初の10個のリスト要素にアクセスするだけですか? – Gautam

11

xsの最初の10個の値だけを出力したいとします。どうすればいい?

だけtakeを使用します。

main = 
do g <- (newMTGen Nothing) 
    xs <- (randoms g) :: IO [Double] 
    mapM_ print $ take 10 xs 

あなたは

XSを書いたIO [ダブル]

を入力しているが、実際に、randoms gIO [Double]型を持つが、おかげでdo表記、xsのタイプが[Double]の場合は、take 10を適用することができます。

あなたはまたliftMを使用して結合スキップできます

ちなみに
main = 
    do g <- newMTGen Nothing 
    ys <- liftM (take 10) $ randoms g :: IO [Double] 
    mapM_ print ys 
関連する問題