来自数据类型的Haskell随机数

Sir*_*lot 5 random haskell

我对Haskell很新.我有一个数据类型:

data Sentence= Prop Int
          | No Sentence
          | And [Sentence]
          | Or [Sentence]
          deriving Eq
Run Code Online (Sandbox Code Playgroud)

我已经为它编写了一个Show实例

但是,无论是否有意义,我希望能够生成随机句子.我怎样才能在Haskell中实现这一目标?

Dar*_*rio 6

随机数生成是"不纯"操作的典型示例,因为调用两次随机生成器当然会产生不同的结果--Haskell的性质不允许这样做.

因此,您需要使用一个Gen a代表随机生成器的a所谓monad ,它在运行时会生成一个type值.

幸运的是,你可以用一个非常好的语法组合这些生成器......

所以,你只需要一些实现这种发生器的 - 我们就这样开始吧.

randomNo   = No <$> randomSentence
randomProp = Prop <$> choose (1, 10) 
[...]

randomSentence = oneOf [randomNo, randomProp, ...]
Run Code Online (Sandbox Code Playgroud)

  • 它只是`fmap` (5认同)

luq*_*qui 5

我最喜欢的方法是使用MonadRandom包.虽然它归结为与传递一些相同的东西RandomGen,它会为你做,并确保你不会陷入过程(例如通过已经使用过的发电机).此外,Rand StdGen a对" as 的概率分布"有很好的解释.

对于您的示例,它可能如下所示:

-- 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
Run Code Online (Sandbox Code Playgroud)

注意那里的幻数5.这样我们就不会获得20亿个元素列表.您可能想要调整随机生成的列表中术语数量的分布.

要运行它,你可以使用evalRandIO或许多其他的东西,比如说:

main = print =<< evalRandIO randSentence
Run Code Online (Sandbox Code Playgroud)