代码之家  ›  专栏  ›  技术社区  ›  Len Tango Ben

Haskell随机数据类型

  •  5
  • Len Tango Ben  · 技术社区  · 14 年前

    我对哈斯克尔很陌生。 我有一个数据类型:

    data Sentence= Prop Int
              | No Sentence
              | And [Sentence]
              | Or [Sentence]
              deriving Eq
    

    然而,不管它是否有意义,我希望能够生成一个随机的句子。

    4 回复  |  直到 14 年前
        1
  •  6
  •   Dario    14 年前

    随机数生成是“不纯”操作的一个典型例子,因为两次调用随机生成器当然会产生不同的结果-Haskell的本性不允许这样做。

    Gen a 这代表了 随机发生器,运行时产生一个 a .

    幸运的是,您可以用一种非常好的语法组合这些生成器。。。

    所以,你只需要一些 library

    randomNo   = No <$> randomSentence
    randomProp = Prop <$> choose (1, 10) 
    [...]
    
    randomSentence = oneOf [randomNo, randomProp, ...]
    
        2
  •  5
  •   luqui    14 年前

    我最喜欢的方法是使用 MonadRandom 包裹。尽管它归结起来和传递一些信息是一样的 RandomGen Rand StdGen a 对“概率分布 a “s”。

    -- a type for probability distributions
    type Dist = Rand StdGen
    
    -- pick uniformly between a list of values
    uniform :: [a] -> Dist a
    uniform xs = do
        ix <- getRandomR (0, length xs - 1)
        return (xs !! ix)
    
    -- return a list of elements generated by the given distribution
    randList :: Int -> Dist a -> Dist [a]
    randList maxElems dist = do
        elems <- getRandomR (0, maxElems)
        sequence (replicate elems dist)
    
    -- return a probability distribution of sentences
    randSentence :: Dist Sentence
    randSentence = do
        -- choose one of these four distributions by a uniform distribution
        -- (uniform [...] returns a distribution of distributions)
        dist <- uniform [
            Prop <$> getRandom,
            No <$> randSentence,
            And <$> randList 5 randSentence,
            Or <$> randList 5 randSentence ]
        -- and sample the one we chose
        dist
    

    注意上面的魔法数字5。所以我们没有20亿个元素列表。您可能需要调整随机生成的列表中术语数量的分布。

    evalRandIO 或者其他很多事情,比如:

    main = print =<< evalRandIO randSentence
    
        3
  •  1
  •   fuz    14 年前

    最简单的方法是使用模块 System.Random

    此模块定义类型类:

    class RandomGen g where
      next :: g -> (Int,g)
      -- ...
    
    class Random r where
      random ::  RandomGen g => g -> (a,g)
      randomR :: RandomGen g => (r,r) -> g -> (a, g)
    

    typeclass,您必须实现的是随机的,特定于第一个函数(因为第二个函数没有意义,您可以像 randomR = const random random ? 你得到一个随机生成器作为输入,你必须生成你所需要的,然后把新的生成器还给你。

    要生成随机值,可以使用 State

    random g = (myResult,gn) where
      (random1,g1) = next g
      (random2,g2) = next g2
      -- ...
    

    randomIO :: Random r => IO r
    

    它是预定义的,每次调用都会产生不同的值。

        4
  •  1
  •   mcandre    13 年前
    pick :: [a] -> IO a
    pick xs = randomRIO (0, length xs - 1) >>= return . (xs !!)