2010-09-22 61 views
5

对于Haskell来说我很新。 我有一个数据类型:Haskell从数据类型中随机输入

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

我已经写了一个显示实例它

然而,是否有意义或不,我希望能够生成一个随机的句子。 我如何在Haskell中完成此任务?

回答

5

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

因此,你需要使用所谓的单子Gen a代表一个随机生成,即在运行时产生a类型的值。

幸运的是,你可以在一个相当不错的语法结合这些发电机...

所以,你只需要一些library实现这种发电机 - 在这里,我们走了。

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

randomSentence = oneOf [randomNo, randomProp, ...] 
+0

感谢您的超快反应,但是您的意思是<$>? – SirLenz0rlot 2010-09-22 12:46:20

+1

啊,它来自'Control.Applicative' - 只是一些简化的语法,这意味着您可以将函数应用于随机值。 – Dario 2010-09-22 12:47:55

+5

这只是'fmap' – fuz 2010-09-22 12:49:15

1

最简单的方法是使用模块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) 

的类型类,你必须实现是随机的,具体的第一功能(作为第二是没有意义的,你可以实现像randomR = const random什么random?你得到一个随机生成的输入,必须生成您所需要的它,并赋予新的发电机回

要生成的随机值,你既可以使用State单子,或者是这样的:。

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

然后,您可以通过此功能使用的系统随机生成:

randomIO :: Random r => IO r 

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

但是,最后你必须决定如何定义你的Random实例。

5

我最喜欢的方法是使用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 
+1

谢谢! 我发现Monad.Random库不包含在最新的Windows软件包中。也许是有原因的?因为当我从它复制粘贴来源(http://www.haskell.org/haskellwiki/NewMonads/MonadRandom)到一个自己的文件时,它会给我错误,我不知道如何解决它:非法实例声明对于'MonadState s(RandT gm)' – SirLenz0rlot 2010-09-23 07:56:19

+1

您需要通过cabal进行安装,而不是复制和粘贴。我假设你已经安装了Haskell平台。然后在命令提示符下执行'cabal install MonadRandom'。您可能需要先“更新cabal”。 – luqui 2010-09-23 16:25:55

1
pick :: [a] -> IO a 
pick xs = randomRIO (0, length xs - 1) >>= return . (xs !!) 

运行挑过任何名单。