在 Quickcheck 中组合不同数据类型的生成器

Combining generator for different datatypes in Quickcheck

我想合并两个不同数据类型的自定义生成器,但它们在另一种数据类型中组合在一起。

在下面的示例中,我想使用 LegumesAnimalProteins 的生成器为蛋白质创建另一个生成器。 chooseelements 不起作用,因为类型不同。将生成器转换为 gen Proteins 也不起作用。

data AnimalProteins = Beef | Chicken | Fish
data Legumes = WhiteBeans | RedBeans | Lentils | Chickpeas

data Proteins = AnimalProteins | Legumes deriving (Show)

rAnimalProteins :: Gen AnimalProteins
rAnimalProteins = elements [Beef , Chicken , Fish]

rLegumes :: Gen Legumes
rLegumes = elements [WhiteBeans , RedBeans , Lentils , Chickpeas]

-- This does not work !
rProteins :: Gen Proteins
rProteins = choose (rLegumes, rAnimalProteins)

解决方案可能很简单,但作为初学者我还是被困在这里。谢谢!

问题是您的 Proteins 数据类型实际上不包含任何 AnimalProteinsLegumes!是的,您以相同的方式命名了 Proteinsconstructors,但是构造函数存在于术语语言中,而不是类型语言中,因此编译器不会自动关联他们到 AnimalProteins type.

为此,您需要明确:

data Proteins = AnimalProteins AnimalProteins | Legumes Legumes

假设您打算将 Proteins 建模为 AnimalProteinsLegumes 之间的选择,您可能需要这样的东西:

data AnimalProteins = Beef | Chicken | Fish deriving (Show, Eq)
data Legumes = WhiteBeans | RedBeans | Lentils | Chickpeas deriving (Show, Eq)

data Proteins = AP AnimalProteins | L Legumes deriving (Show, Eq)

您可以像这样组合生成器:

rAnimalProteins :: Gen AnimalProteins
rAnimalProteins = elements [Beef, Chicken, Fish]

rLegumes :: Gen Legumes
rLegumes = elements [WhiteBeans, RedBeans, Lentils, Chickpeas]

rProteins :: Gen Proteins
rProteins = oneof [fmap AP rAnimalProteins, fmap L rLegumes]

rAnimalProteinsrLegumes 是您已经定义的。您可以使用 fmap 'lift' 将它们分成两个单独的 Gen Proteins 值,因为 GenFunctor.

例如,fmap AP rAnimalProteinsGen Legumes 值映射到 Gen Proteins 值,方法是映射每个生成的 Legumes 值并用 AP 数据包装它构造函数。虽然它是一个 Gen Proteins 值,但它始终会创建 AP 个值,即 AP BeefAP ChickenAP Fish.

同样,fmap L rLegumesrLegumesGen Legumes 提升到 Gen Proteins。它将始终生成值 L WhiteBeansL RedBeansL LentilsL Chickpeas.

之一

通过使用 oneof,您可以将两个专用生成器组合成一个更复杂的生成器,该生成器随机选择其中一个生成器来生成值。