Haskell随机数据类型

Haskell随机数据类型,haskell,random,Haskell,Random,我是哈斯克尔的新手。 我有一个数据类型: data Sentence= Prop Int | No Sentence | And [Sentence] | Or [Sentence] deriving Eq 我已经为它写了一个展示实例 然而,不管它是否有意义,我希望能够生成一个随机的句子。 如何在Haskell中实现这一点?随机数生成是“不纯”操作的典型示例,因为调用两次随机生成器当然会产生不同的结果-Haskel

我是哈斯克尔的新手。 我有一个数据类型:

data Sentence= Prop Int
          | No Sentence
          | And [Sentence]
          | Or [Sentence]
          deriving Eq
我已经为它写了一个展示实例

然而,不管它是否有意义,我希望能够生成一个随机的句子。
如何在Haskell中实现这一点?

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

因此,您需要使用一个所谓的monad
gena
,它表示一个随机生成器,当运行该生成器时,生成一个
a
类型的值

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

所以,您只需要一些实现这样一个生成器的工具-我们开始吧

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

randomSentence = oneOf [randomNo, randomProp, ...]
randomNo=无随机语句
randomProp=道具选择(1,10)
[...]
RandomSequence=其中一个[randomNo,randomProp,…]

最简单的方法是使用该模块,它位于随机软件包中,因此您可能必须首先安装它

此模块定义类型类:

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
monad,或者类似的方法:

random g = (myResult,gn) where
  (random1,g1) = next g
  (random2,g2) = next g2
  -- ...
-- 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
然后,您可以通过以下功能使用系统随机生成器:

randomIO :: Random r => IO r
它是预定义的,每次调用都会产生不同的值


然而,最后你必须自己决定如何定义你的随机实例。

我最喜欢的方法是使用这个包。虽然它归结起来与传递一些
RandomGen
是一样的,但它可以为你做这件事,并确保你不会在这个过程中搞砸(比如传递一个已经使用过的生成器)此外,
randstdgena
对“as的概率分布”有很好的解释

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

random g = (myResult,gn) where
  (random1,g1) = next g
  (random2,g2) = next g2
  -- ...
-- 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

运行任意列表。

谢谢您的超快速响应,但您的意思是什么?啊,它来自
控件。Applicative
-只是一些简化的语法,这意味着您可以将函数应用于随机值。啊,好的,但是,当我测试您的代码时,Haskell说:不在范围内:'oneOf',但它应该在Quickcheck中,对吗?是的,您会发现ed Test.QuickCheck和System.Random(Control.Applicative和Control.Monad对于一些额外的功能/语法也非常好)奇怪的是,它能识别导入,但仍然不能识别其中的一个。谢谢!我发现Monad.Random库没有包含在最新的windows软件包中。也许是因为某种原因?从我复制粘贴源代码时开始()在一个自己的文件中,它给了我一些我不知道如何解决的错误:MonadState s(RandT g m)的非法实例声明'您需要通过cabal安装,而不是复制和粘贴。我假设您已经安装了Haskell平台。然后在命令提示下执行
cabal安装MonadRandom
。您可能需要先
cabal更新