Haskellで乱数を取得しようとしています。(私は現在学んでおり、Monads や IO などに取り組んでいません) 問題は、System.Random の関数がすべて IO Int を返すことです。これは、使用する残りのコードでは使用できません。イントとフロート。
ここでの目的は、ペアの最初のペアが確率を表す float であるリストからペアを選択することです。そこで私の計画は、乱数を使用してその確率に基づいてペアを選択することでした。
すでに述べたように、乱数は純粋な値にはなり得ません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'dList
IO
Double
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
ます。
これらの答えがすべてではないと思います。私のシミュレーションでは、乱数を遅延して生成し、小さい (私の 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