3

ランダムに生成された 6 桁の数字が必要です。この関数を 1000 回以上呼び出さないことが保証されています。関数は、呼び出すたびに個別の番号を返すことができるはずです。

nextRandom引数なしのようにこの関数を呼び出したいです。Haskell には、私に適したライブラリはありますか? 種子を維持することはできません。Haskell は現在時刻を として使用できますseed

更新: 問題のコンテキスト。

グラフ (ドット形式) を生成しており、すべての頂点に個別のラベルがあることを確認したいと考えています。発生時刻をラベルとして付ければいいのですが、乱数を発生させてそうするという発想に噛みつきました。

4

4 に答える 4

7

純粋な関数 (nextRandom引数のない など) は、数学関数に似ています。すべての呼び出しで、同じ引数で同じ結果が生成されます。

だからあなたが求めていることは不可能です。

  • 乱数が必要です。
  • 関数には、どの数値が既に生成されているかを知るための何らかのメモリがあると予想されます。

Haskell の方法で、シードまたは乱数ジェネレーターを関数に渡すか、モナドを使用します。それが役立つ場合は、事前に 1000 個の番号を作成してから、リストから取得できます。

于 2013-06-30T11:56:10.227 に答える
6

毎回異なる数値を返す純粋な関数を持つことはできません。その出力は、引数だけではなく、以前の呼び出しに依存します。しかし、これまでに生成された数のセットを保持するモナドを作成し、まだ生成されていない数が見つかるまで乱数の生成を再試行することができます。次の例では、MonadRandomパッケージを使用しました。

import Control.Monad
import Control.Monad.Random
import Control.Monad.State
import Data.IntSet (IntSet)
import qualified Data.IntSet as IS
import System.Random (getStdGen)

type RandDistinct g a = StateT IntSet (Rand g) a

evalDistinct :: RandomGen g => RandDistinct g a -> g -> a
evalDistinct k = evalRand (evalStateT k IS.empty)

上記のタイプはStateT、乱数ジェネレーターを拡張して、これまでに生成された数値のセットを記憶するために使用します。このモナドで計算を評価したいときは、空のセットから始めて、内部の計算を で評価しevalRandます。

これで、毎回異なる数値を返す関数を書くことができます:

nextDistinct :: RandomGen g => (Int,Int) -> RandDistinct g Int
nextDistinct range = loop
  where
    -- Loop until we find a number not in the set
    loop = do
        set <- get
        r <- getRandomR range
        if IS.member r set
          then loop -- repeat
          else put (IS.insert r set) >> return r

そして、それがどのように機能するかをテストします:

main = getStdGen >>= print . evalDistinct (replicateM 50 $ nextDistinct (10, 99))

nextDistinct単純な戦略を使用することに注意してください-セットに既に存在する場合は、新しい番号の生成を再試行してください。衝突の数が少ない限り、これは問題なく機能します。

于 2013-06-30T15:05:11.170 に答える
1

あなたが求めている機能が使用されるコンテキストについて、ここでさらに役立つかもしれません。私は専門家ではありませんが、このようなことはあなたを助けますか?

import Control.Monad.Random

rnd :: (RandomGen g) => Rand g Int
rnd = getRandomR (100000,999999)

main = do
  putStr "\nPlease type 'nextRandom' or 'quit':\n> "
  mainLoop [] where
    mainLoop memory = do
      command <- getLine
      case command of
        "nextRandom" -> do next <- randomLoop memory
                           putStr (show next ++ "\n> ")
                           mainLoop (next:memory)
        "quit"       -> return ()
        otherwise    -> putStr "\n> "
    randomLoop memory = do  
      value <- evalRandIO rnd
      if elem value memory 
         then randomLoop memory
         else return value
于 2013-06-30T14:03:11.143 に答える
1

まさにあなたが探しているものではありませんが、置換なしの一般的なサンプリング ルーチンが必要な場合は、SO に関する別の質問のために作成したこのサンプル モジュールのようなものを使用できます。

事前に必要な数の異なる 6 桁の数字を生成し、好きな場所で使用するだけです。元:

import System.Random.MWC
import Sample

main :: IO ()
main = do
  ns <- withSystemRandom . asGenIO $ \gen -> sample [100000..999999] 10 gen
  print ns

-- [754056,765889,795475,389702,120426,740641,556446,490338,534738,213852]
于 2013-06-30T21:18:21.073 に答える