[英]Haskell QuickCheck generating values within a function
How do I get this contrived example to work?我如何让这个人为的例子起作用?
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]
It gives compiler error:它给出了编译器错误:
* 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))'
The problem is choose (0, 1)
does not produce an Int
, it produces a Gen Int
.问题是choose (0, 1)
不会产生Int
,它会产生Gen Int
。
You're treating it as though it were an Int
in this expression:您将其视为此表达式中的Int
:
pure $ g (\i -> i + choose (0, 1))
Since Gen Int
is a monad you need to bind it in order to use the result of the "choice".由于Gen Int
是一个 monad,您需要绑定它才能使用“选择”的结果。
Something like this:像这样的东西:
instance Arbitrary Q where
arbitrary :: Gen Q
arbitrary = do
choice <- choose (0, 1)
return $ g (\i -> i + choice)
Responding to the edited question:回复已编辑的问题:
The issue is still the same, you're trying to use the Gen Int
as though it were an Int
.问题仍然相同,您尝试使用Gen Int
,就好像它是Int
一样。 You can bind multiple times inside a do
.您可以在do
内多次绑定。
Here is a solution:这是一个解决方案:
instance Arbitrary Q where
arbitrary :: Gen Q
arbitrary = do
len <- choose (1, 5)
choice <- choose (0, 1)
return $ g len (\i -> i + choice)
Responding to the edited, edited question :回复已编辑、已编辑的问题:
You have to propagate the side effects somewhere, this just means you need to run choose
len
times.您必须在某处传播副作用,这仅意味着您需要运行choose
len
次。 Because g
is a "library" function, I'm going to assume that you have no control over it, and can't change it.因为g
是一个“库”function,所以我假设您无法控制它,也无法更改它。 Note that the solution below is ugly since I need to use the partial function (!!)
, and because it is rather slow (there is probably a better way to do this, but I'm not able to find it).请注意,下面的解决方案很难看,因为我需要使用部分 function (!!)
,并且因为它相当慢(可能有更好的方法来做到这一点,但我找不到它)。
The trick here is I'm mapping a function that returns len
Gen Int
's, and then runs all of them, producing a list of chosen numbers (see mapM
description for more details).这里的诀窍是我正在映射一个返回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.