繁体   English   中英

Haskell QuickCheck 在 function 中生成值

[英]Haskell QuickCheck generating values within a function

我如何让这个人为的例子起作用?

newtype Q = Q [Int]

instance Arbitrary Q where
    arbitrary :: Gen Q
    arbitrary = do
        len <- choose (1, 5)
        pure $ g len (\ i -> i + choose (0, 1)) -- want different choice for each invocation

g :: Int -> (Int -> Int) -> Q -- g is a library function
g len f = Q $ fmap f [1 .. len]

它给出了编译器错误:

    * Couldn't match expected type `Int' with actual type `Gen a0'
    * In the second argument of `(+)', namely `choose (0, 1)'
      In the expression: i + choose (0, 1)
      In the second argument of `g', namely `(\ i -> i + choose (0, 1))'

问题是choose (0, 1)不会产生Int ,它会产生Gen Int

您将其视为此表达式中的Int

pure $ g (\i -> i + choose (0, 1))

由于Gen Int是一个 monad,您需要绑定它才能使用“选择”的结果。

像这样的东西:

instance Arbitrary Q where
    arbitrary :: Gen Q
    arbitrary = do
        choice <- choose (0, 1)
        return $ g (\i -> i + choice)

回复已编辑的问题:

问题仍然相同,您尝试使用Gen Int ,就好像它是Int一样。 您可以在do内多次绑定。

这是一个解决方案:

instance Arbitrary Q where
    arbitrary :: Gen Q
    arbitrary = do
        len <- choose (1, 5)
        choice <- choose (0, 1)
        return $ g len (\i -> i + choice)

回复已编辑、已编辑的问题

您必须在某处传播副作用,这仅意味着您需要运行choose len次。 因为g是一个“库”function,所以我假设您无法控制它,也无法更改它。 请注意,下面的解决方案很难看,因为我需要使用部分 function (!!) ,并且因为它相当慢(可能有更好的方法来做到这一点,但我找不到它)。

这里的诀窍是我正在映射一个返回len Gen Int的 function,然后运行所有这些,生成一个选定数字的列表(有关更多详细信息,请参见mapM描述)。

instance Arbitrary Q where
 arbitrary :: Gen Q
 arbitrary = do
     len <- choose (1, 5)
     choices <- mapM (\_ -> choose (0, 1)) [1 .. len]
     return $ g len (\i -> i + (choices !! i))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM