涉及具有构造函数函数的数据类型的 QuickCheck 问题
Issues with QuickCheck involving a data type with a function as a constructor
写了下面的代码,但遇到了一些问题:
我收到的错误是:数据构造函数不在范围内:Int :: Int
如果我从我的数组中删除 Numeric Int 元素,代码工作得很好,但是 Numeric Int 是 Rank 类型的构造函数,所以它也应该被包括在内,但我不确定如何在不出现此错误的情况下包括它生产。
下面是代码,如果这个问题冗长或愚蠢,我深表歉意,这是我在 Whosebug 上的第一个 post,因此对于如何提出这个问题的任何反馈也将不胜感激。
任何帮助将不胜感激
import Test.QuickCheck
import Data.Data
import Data.Typeable
data Suit = Spades | Hearts | Clubs | Diamonds
deriving Show
data Colour = Black | Red
deriving Show
colour :: Suit -> Colour
colour Spades = Black
colour Hearts = Red
colour Diamonds = Red
colour Clubs = Black
data Rank = Numeric Int | Jack | Queen | King | Ace
deriving Show
rankBeats :: Rank -> Rank -> Bool
rankBeats _ Ace = False
rankBeats Ace _ = True
rankBeats _ King = False
rankBeats King _ = True
rankBeats _ Queen = False
rankBeats Queen _ = True
rankBeats _ Jack = False
rankBeats Jack _ = True
rankBeats (Numeric m) (Numeric n) = m > n
prop_rankBeats :: Rank -> Rank -> Bool
prop_rankBeats a b = rankBeats a b || rankBeats b a
instance Arbitrary Rank where
arbitrary = elements [Numeric Int,Jack, Queen, King, Ace]
您的 Arbitrary
实例 Rank
包含 Int
:
instance Arbitrary Rank where
-- an Int ↓
arbitrary = elements [Numeric Int, Jack, Queen, King, Ace]
但是Int
不是数据构造函数,而是类型构造函数。你不能使用这个。
您可以做的是制作一个如下所示的生成器:
instance Arbitrary Rank where
arbitrary = oneof ((<strong>Numeric <$> arbitrary</strong>) : map <strong>pure</strong> [Jack, Queen, King, Ace])
这里第一项Numeric <$> arbitrary
会使用Int
类型的Arbitrary
实例,而且我们使用map pure [Jack, Queen, King, Ace]
来转换这些Rank
s到 Gen Rank
秒。然后 oneof :: [Gen a] -> Gen a
每次都会从列表中选择一个随机生成器。 oneof
将挑选重量相等的物品。例如,我们可以使用 frequency
来选择具有不同权重的这些:
{-# LANGUAGE TupleSections #-}
instance Arbitrary Rank where
arbitrary = frequency ((9, <strong>Numeric <$> chooseInt (2,10)</strong>) : map <strong>((1,) . pure)</strong> [Jack, Queen, King, Ace])
这里更公平:13 次中有 9 次,它会选择一个 Numeric
,我们使用 chooseInt (2, 10)
这样我们只在 [=27] 之间生成 Int
s =] 和 10
.
Willem的代码也可以泛化推导。
使用包 generic-random:
{-# Language DataKinds #-}
{-# Language DeriveGeneric #-}
{-# Language DerivingVia #-}
import GHC.Generics
import Generic.Random.DerivingVia
import Test.QuickCheck
-- ghci> :set -XTypeApplications
-- ghci> sample @Rank arbitrary
-- King
-- Queen
-- King
-- Jack
-- Numeric (-4)
-- Numeric (-9)
-- Jack
-- Jack
-- Queen
-- Ace
-- Queen
data Rank = Numeric Int | Jack | Queen | King | Ace
deriving
stock (Show, Generic)
deriving Arbitrary
via GenericArbitraryU Rank
增加权重(如frequency
):
-- ghci> sample @Rank arbitrary
-- Numeric 0
-- Queen
-- Numeric (-4)
-- Numeric (-6)
-- Numeric 4
-- Numeric 3
-- Numeric 9
-- Numeric (-3)
-- Numeric 12
-- Jack
-- Numeric 20
data Rank = Numeric Int | Jack | Queen | King | Ace
deriving
stock (Show, Generic)
deriving Arbitrary
via GenericArbitrary '[9, 1, 1, 1, 1] Rank
我们甚至可以用 generic-override 实现 choose (2, 10)
!
{-# Language InstanceSigs #-}
{-# Language ScopedTypeVariables #-}
{-# Language StandaloneKindSignatures #-}
{-# Language TypeApplications #-}
{-# Language TypeOperators #-}
..
import Data.Kind
import Data.Proxy
import GHC.TypeLits
import System.Random
-- ghci> sample @Rank arbitrary
-- King
-- Numeric 10
-- Queen
-- Jack
-- Jack
-- King
-- Numeric 8
-- Numeric 7
-- Numeric 4
-- Numeric 4
-- Numeric 6
data Rank = Numeric Int | Jack | Queen | King | Ace
deriving
stock (Show, Generic)
deriving Arbitrary
via GenericArbitrary '[9, 1, 1, 1, 1]
(Override Rank '[Int `With` Choose 2 10])
正在使用
type Choose :: Nat -> Nat -> Type -> Type
newtype Choose n m a = Choose a
instance (KnownNat n, KnownNat m, Num a, Random a) => Arbitrary (Choose n m a) where
arbitrary :: Gen (Choose n m a)
arbitrary = Choose <$> choose (fromInteger (natVal @n Proxy), fromInteger (natVal @m Proxy))
写了下面的代码,但遇到了一些问题:
我收到的错误是:数据构造函数不在范围内:Int :: Int
如果我从我的数组中删除 Numeric Int 元素,代码工作得很好,但是 Numeric Int 是 Rank 类型的构造函数,所以它也应该被包括在内,但我不确定如何在不出现此错误的情况下包括它生产。
下面是代码,如果这个问题冗长或愚蠢,我深表歉意,这是我在 Whosebug 上的第一个 post,因此对于如何提出这个问题的任何反馈也将不胜感激。
任何帮助将不胜感激
import Test.QuickCheck
import Data.Data
import Data.Typeable
data Suit = Spades | Hearts | Clubs | Diamonds
deriving Show
data Colour = Black | Red
deriving Show
colour :: Suit -> Colour
colour Spades = Black
colour Hearts = Red
colour Diamonds = Red
colour Clubs = Black
data Rank = Numeric Int | Jack | Queen | King | Ace
deriving Show
rankBeats :: Rank -> Rank -> Bool
rankBeats _ Ace = False
rankBeats Ace _ = True
rankBeats _ King = False
rankBeats King _ = True
rankBeats _ Queen = False
rankBeats Queen _ = True
rankBeats _ Jack = False
rankBeats Jack _ = True
rankBeats (Numeric m) (Numeric n) = m > n
prop_rankBeats :: Rank -> Rank -> Bool
prop_rankBeats a b = rankBeats a b || rankBeats b a
instance Arbitrary Rank where
arbitrary = elements [Numeric Int,Jack, Queen, King, Ace]
您的 Arbitrary
实例 Rank
包含 Int
:
instance Arbitrary Rank where
-- an Int ↓
arbitrary = elements [Numeric Int, Jack, Queen, King, Ace]
但是Int
不是数据构造函数,而是类型构造函数。你不能使用这个。
您可以做的是制作一个如下所示的生成器:
instance Arbitrary Rank where
arbitrary = oneof ((<strong>Numeric <$> arbitrary</strong>) : map <strong>pure</strong> [Jack, Queen, King, Ace])
这里第一项Numeric <$> arbitrary
会使用Int
类型的Arbitrary
实例,而且我们使用map pure [Jack, Queen, King, Ace]
来转换这些Rank
s到 Gen Rank
秒。然后 oneof :: [Gen a] -> Gen a
每次都会从列表中选择一个随机生成器。 oneof
将挑选重量相等的物品。例如,我们可以使用 frequency
来选择具有不同权重的这些:
{-# LANGUAGE TupleSections #-}
instance Arbitrary Rank where
arbitrary = frequency ((9, <strong>Numeric <$> chooseInt (2,10)</strong>) : map <strong>((1,) . pure)</strong> [Jack, Queen, King, Ace])
这里更公平:13 次中有 9 次,它会选择一个 Numeric
,我们使用 chooseInt (2, 10)
这样我们只在 [=27] 之间生成 Int
s =] 和 10
.
Willem的代码也可以泛化推导。
使用包 generic-random:
{-# Language DataKinds #-}
{-# Language DeriveGeneric #-}
{-# Language DerivingVia #-}
import GHC.Generics
import Generic.Random.DerivingVia
import Test.QuickCheck
-- ghci> :set -XTypeApplications
-- ghci> sample @Rank arbitrary
-- King
-- Queen
-- King
-- Jack
-- Numeric (-4)
-- Numeric (-9)
-- Jack
-- Jack
-- Queen
-- Ace
-- Queen
data Rank = Numeric Int | Jack | Queen | King | Ace
deriving
stock (Show, Generic)
deriving Arbitrary
via GenericArbitraryU Rank
增加权重(如frequency
):
-- ghci> sample @Rank arbitrary
-- Numeric 0
-- Queen
-- Numeric (-4)
-- Numeric (-6)
-- Numeric 4
-- Numeric 3
-- Numeric 9
-- Numeric (-3)
-- Numeric 12
-- Jack
-- Numeric 20
data Rank = Numeric Int | Jack | Queen | King | Ace
deriving
stock (Show, Generic)
deriving Arbitrary
via GenericArbitrary '[9, 1, 1, 1, 1] Rank
我们甚至可以用 generic-override 实现 choose (2, 10)
!
{-# Language InstanceSigs #-}
{-# Language ScopedTypeVariables #-}
{-# Language StandaloneKindSignatures #-}
{-# Language TypeApplications #-}
{-# Language TypeOperators #-}
..
import Data.Kind
import Data.Proxy
import GHC.TypeLits
import System.Random
-- ghci> sample @Rank arbitrary
-- King
-- Numeric 10
-- Queen
-- Jack
-- Jack
-- King
-- Numeric 8
-- Numeric 7
-- Numeric 4
-- Numeric 4
-- Numeric 6
data Rank = Numeric Int | Jack | Queen | King | Ace
deriving
stock (Show, Generic)
deriving Arbitrary
via GenericArbitrary '[9, 1, 1, 1, 1]
(Override Rank '[Int `With` Choose 2 10])
正在使用
type Choose :: Nat -> Nat -> Type -> Type
newtype Choose n m a = Choose a
instance (KnownNat n, KnownNat m, Num a, Random a) => Arbitrary (Choose n m a) where
arbitrary :: Gen (Choose n m a)
arbitrary = Choose <$> choose (fromInteger (natVal @n Proxy), fromInteger (natVal @m Proxy))