32

Haskellで乱数を取得しようとしています。(私は現在学んでおり、Monads や IO などに取り組んでいません) 問題は、System.Random の関数がすべて IO Int を返すことです。これは、使用する残りのコードでは使用できません。イントとフロート。

ここでの目的は、ペアの最初のペアが確率を表す float であるリストからペアを選択することです。そこで私の計画は、乱数を使用してその確率に基づいてペアを選択することでした。

4

5 に答える 5

6

すでに述べたように、乱数は純粋な値にはなり得ません1

ただし、これは本当に気にする必要はありません。逆に考えてみてください。他の言語には純粋な値などというものはありません。それは常に、あなたが扱っている現実世界の干渉を伴う状態です。Haskell もIOモナドでそれを行うことができます。それがどのように機能するかを正確に知る必要はありません。手続き型言語でどのように見えるかを模倣するだけです (ただし、ここにはいくつかの落とし穴があります)。

まず第一に、言語とはまったく関係のないアルゴリズムが必要です。明らかな方法は、リスト全体で確率を累積し、結果のステップ関数を [0, 1[ から目的の値へのマップとして使用することです。

probsListLookup :: [(Double, a)] -> Double -> a
probsListLookup pAssoc = look acc'dList
 where acc'dList = scanl1 (\(pa,_) (pn,x) -> (pa+pn,x)) pAssoc
       look ((pa, x) : pas) rval
         | rval < pa   = look pas rval
         | otherwise   = x

これは無効な入力を適切に処理せず (確率が 1 にならないなど)、要求された値ごとにO ( n ) をスクランブルして効率的ではないことに注意してください2。ただし、もっと重要なのは、これが純粋な関数であることに注意してください。一般的には、できるだけ純粋な関数を使用し、絶対に必要な場合にのみ使用することをお勧めします。今のように: 0 と 1 の間の単一の値を取得する必要があります。簡単です!acc'dListIODouble

main = do
   lookupVal <- randomRIO (0, 1)
   print $ probsListLookup [(0.1, 1), (0.2, 2), (0.3, 4), (0.4, 5)] lookupVal

1少なくともInt;のような基本的なタイプではありません。ただし、実際には確率分布全体で「純粋な計算」を行うことができます。これを明示的に行うのは非常に面倒ですが、Haskell では特定のモナド(または実際には comonads ) を使用して、Haskell IO (または任意の非純粋な言語) と同じくらい簡単に、入出力の危険を冒さずに行うことができます。

2などで改善できData.Mapます。

于 2013-10-25T17:14:13.170 に答える
3

これらの答えがすべてではないと思います。私のシミュレーションでは、乱数を遅延して生成し、小さい (私の macbook では 1.1M) スペース フットプリントで厳密に実行してそれらを消費します。

おそらく、乱数は IO モナドにしか存在できないという発言は、実際には乱数を指していますが、疑似乱数についてはそうではなく、通常は結果を再現できるようにしたいと考えています。次に例を示します。

module Main (
  main
  ) where

import qualified Data.Vector.Unboxed as V
import Data.Random.Source.PureMT
import Data.Random
import Control.Monad.State

nItt :: Int
nItt = 1000000000

gridSize :: Int
gridSize = 10

testData :: Int -> V.Vector Double
testData m =
  V.fromList $
  evalState (replicateM m (sample (uniform (0 :: Double) 1.0)))
  (pureMT 2)

test = V.foldl (+) 0 (testData nItt)

main = putStrLn $ show test
于 2014-03-05T07:56:46.680 に答える