2015-10-01 550 views
1

加权数我是新来的Haskell和我想产生一个数独的任意单元格的随机数加权随机产生在Haskell

90% of the time, it should generate Nothing 
10% of the time, it should generate a random value between 1 and 9 

这就是我想出迄今(它不会编译)

-- cell generates an arbitrary cell in a Sudoku 
-- cell :: Gen (Maybe Int) 


cell = case x of 1 -> return (Just y); _ -> return Nothing 
     where std = mkStdGen(100) 
       (x, a) = randomR(1, 10) std 
       (y, a')= randomR(1, 9) std 

任何帮助,在得到它来编译,或者指着我推向一个更好的方法是非常赞赏


使用快速检查我这是怎么做的:

-- cell generates an arbitrary cell in a Sudoku 
cell :: Gen (Maybe Int) 
cell = frequency [(9, return Nothing), 
       (1, do r <- choose (1,9); return (Just r))]   

-- an instance for generating Arbitrary Sudokus 
instance Arbitrary Sudoku where 
    arbitrary = 
    do rows <- sequence [ sequence [ cell | j <- [1..9] ] | i <- [1..9] ] 
     return (Sudoku rows) 

回答

2

如果使用快速检查,你肯定不希望cell到纯值 - randomR (0,100) (mkStdGen 43434343)不是随机的任何,所以这将是对你没用供测试用。

由于您使用的是QuickCheck,因此您需要使用QuickCheck功能。你不能轻易使用System.Random也不应该。只需使用(相当强大的)QuickCheck API,它具有功能choose :: Random a => (a,a) -> Gen a,它选择范围内的一个随机数,以及一个函数frequency :: [(Int, Gen a)] -> Gen a,它根据它的权重(即可能性)选择一个随机生成器,并返回该生成器。你可以写cell为:

cell :: Gen (Maybe Int) 
cell = frequency 
    [ (1, Just `fmap` choose (1,9)) 
    , (9, return Nothing) 
    ] 

然后,例如,如果你定义你的独板为data Sudoku = Sudoku [[Maybe Int]],你可以随便写一个Arbitrary例如,它使用cell为:

import Control.Monad (replicateM) 

instance Arbitrary Sudoku where 
    arbitrary = Sudoku `fmap` replicateM 9 (replicateM 9 cell) 
+0

我意识到,快速检查了一些功能使得我能够更轻松地做我想做的事情,起初我没有意识到它具有实现随机性的功能。 我编辑的帖子包括我是如何做到的,我没有使用fmap和replicateM(我真的不知道他们在做什么),但我认为我们的解决方案非常相似 – Pro9

+0

我们的解决方案是相同的! (就像你基本上只是内联了'fmap'和'replicateM'的定义一样。)为了将来的参考,'fmap'就像'map',但是对于其他数据类型 - 在这种情况下,它被用于'( a - > b) - >(Gen a - > Gen b)' - 所以基本上它只是'提升'一个函数来修改'Gen'中的一个值,并且你完全一样,但是'do'符号。而'replicateM n'就是'序列。复制n' - 用列表理解代替复制,然后调用'sequence',实现相同的效果。 – user2407038