Haskell QuickCheck 在函数内生成值
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 你需要绑定它才能使用 "choice".
的结果
像这样:
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
是一个 "library" 函数,所以我假设您无法控制它,也无法更改它。请注意,下面的解决方案很丑陋,因为我需要使用部分函数 (!!)
,而且它相当慢(可能有更好的方法来执行此操作,但我找不到它)。
这里的诀窍是我正在映射一个 returns len
Gen Int
的函数,然后 运行 所有这些函数,生成一个列表所选号码(有关详细信息,请参阅 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))
如何让这个人为的例子起作用?
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 你需要绑定它才能使用 "choice".
像这样:
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
是一个 "library" 函数,所以我假设您无法控制它,也无法更改它。请注意,下面的解决方案很丑陋,因为我需要使用部分函数 (!!)
,而且它相当慢(可能有更好的方法来执行此操作,但我找不到它)。
这里的诀窍是我正在映射一个 returns len
Gen Int
的函数,然后 运行 所有这些函数,生成一个列表所选号码(有关详细信息,请参阅 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))