我对Haskell很新.我有一个数据类型:
data Sentence= Prop Int
| No Sentence
| And [Sentence]
| Or [Sentence]
deriving Eq
Run Code Online (Sandbox Code Playgroud)
我已经为它编写了一个Show实例
但是,无论是否有意义,我希望能够生成随机句子.我怎样才能在Haskell中实现这一目标?
随机数生成是"不纯"操作的典型示例,因为调用两次随机生成器当然会产生不同的结果--Haskell的性质不允许这样做.
因此,您需要使用一个Gen a代表随机生成器的a所谓monad ,它在运行时会生成一个type值.
幸运的是,你可以用一个非常好的语法组合这些生成器......
所以,你只需要一些实现这种发生器的库 - 我们就这样开始吧.
randomNo = No <$> randomSentence
randomProp = Prop <$> choose (1, 10)
[...]
randomSentence = oneOf [randomNo, randomProp, ...]
Run Code Online (Sandbox Code Playgroud)
我最喜欢的方法是使用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)