簡體   English   中英

使用頻率選擇 Haskell QuickCheck

[英]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會導致相同的錯誤。

由於您似乎想在IB構造函數之間均勻分布,因此更簡單的解決方案是使用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

genIgenB生成器通過將原始整數和 Boolean 值映射到各自的 case 構造函數來使用IntBool的底層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-random1.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM