[英]Using choose in frequency Haskell QuickCheck
所以我有下面的代碼,我試圖讓它成為Arbitrary
的一個實例:
data MyData = I Int | B Bool
instance Arbitrary MyData where
arbitrary = do {
frequency [(1, return (I 1)),
(1, return (choose((B True), (B False))))]
}
然而,有了這個我得到(可以理解的)錯誤:
Couldn't match type ‘Gen MyData’ with ‘MyData’
Expected type: Gen MyData
Actual type: Gen (Gen MyData)
我怎樣才能完成這個? 另外,我想用隨機Int
返回I
而不是 ( I 1
)。 但是,使用arbitrary
function 而不是1
會導致相同的錯誤。
由於您似乎想在I
和B
構造函數之間均勻分布,因此更簡單的解決方案是使用oneof而不是frequency
:
data MyData = I Int | B Bool deriving (Eq, Show)
instance Arbitrary MyData where
arbitrary = oneof [genI, genB]
where genI = fmap I arbitrary
genB = fmap B arbitrary
genI
和genB
生成器通過將原始整數和 Boolean 值映射到各自的 case 構造函數來使用Int
和Bool
的底層Arbitrary
實例。
這是一組示例數據:
> sample (arbitrary :: Gen MyData)
B False
B False
I 2
B False
I 1
I 7
B False
B False
B True
I 7
B False
如您所見,它還可以選擇任意整數。
OP 中的代碼有幾個問題。 第一條錯誤消息是返回類型是嵌套的。 解決這個問題的一種方法是刪除do
符號。 然而,這並不能解決問題。
即使您將其縮減為以下內容,它也不會進行類型檢查:
instance Arbitrary MyData where
arbitrary =
frequency [(1, return (I 1)),
(1, choose(B True, B False))]
此嘗試產生錯誤:
Q72160684.hs:10:21: error:
* No instance for (random-1.1:System.Random.Random MyData)
arising from a use of `choose'
* In the expression: choose (B True, B False)
In the expression: (1, choose (B True, B False))
In the first argument of `frequency', namely
`[(1, return (I 1)), (1, choose (B True, B False))]'
|
10 | (1, choose(B True, B False))]
| ^^^^^^^^^^^^^^^^^^^^^^^
choose
方法要求輸入是Random
實例,而MyData
不是。
如果您真的想使用frequency
而不是oneof
,最簡單的方法可能是首先讓oneof
起作用,因為您可以將frequency
視為oneof
的概括。
首先,為了使代碼更簡潔一些,我使用<$>
而不是fmap
,然后內聯了兩個生成器:
instance Arbitrary MyData where
arbitrary = oneof [I <$> arbitrary, B <$> arbitrary]
現在將oneof
替換為frequency
並將每個生成器更改為加權元組:
instance Arbitrary MyData where
arbitrary = frequency [(10, I <$> arbitrary), (1, B <$> arbitrary)]
從這個實例中抽樣說明分布現在是傾斜的:
> sample (arbitrary :: Gen MyData)
I 0
I (-2)
I (-4)
I (-1)
I 0
I 8
B True
I 1
I 3
I (-3)
I (-16)
有 10 個I
值,只有 1 個B
值。
您可以使用generic-random (從1.5.0.0開始)派生它。
通過GenericArbitraryU
派生:提供均勻分布(如 Mark oneof
的回答中的一個):
{-# Language DataKinds #-}
{-# Language DeriveGeneric #-}
{-# Language DerivingVia #-}
import Test.QuickCheck
import GHC.Generics
import Generic.Random.DerivingVia
-- ghci> :set -XTypeApplications
-- ghci> sample @MyData arbitrary
-- I 0
-- I 1
-- B True
-- I 6
-- I (-5)
-- I (-7)
-- B True
-- I (-10)
-- B True
-- B True
-- I (-9)
data MyData = I Int | B Bool
deriving
stock (Show, Generic)
deriving Arbitrary
via GenericArbitraryU MyData
通過GenericArbitrary
推導:給出由類型級數字列表指定的加權分布。 它們表示每個構造函數的頻率(如frequency
):
-- ghci> sample @MyData arbitrary
-- I 0
-- I (-2)
-- I 4
-- I 5
-- I 2
-- I 0
-- B False
-- I (-9)
-- I (-10)
-- I (-3)
-- I (-8)
data MyData = I Int | B Bool
deriving
stock (Show, Generic)
deriving Arbitrary
via GenericArbitrary '[10, 1] MyData
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.