首页 > 解决方案 > 为复杂类型创建任意实例

问题描述

我正在尝试使用 QuickCheck 检查我的代码,因此我需要Arbitrary为我的类型创建实例。一种data Schedule是复杂的,不知道如何正确对待。三个实例(for Date, Activity, TimeStart)工作正常。但是最后一个实例 (for Schedule) 不正确,我寻求帮助来修复它。

data Schedule = Schedule [(Date,[Activity])]
data Date = Date Year Month Day
data Activity = Activity (ActivityName,TimeStart)
data TimeStart = TimeStart Hour Minute

type Year = Integer
type Month = Integer
type Day = Integer
type ActivityName = String
type Hour = Integer
type Minute = Integer

instance Arbitrary Date where
  arbitrary = do
    year <- choose (2000, 2050)
    month <- choose (1, 12)
    day <- choose (1, 28)
    return $ Date year month day

instance Arbitrary Activity where
  arbitrary = do
    size <- choose (5, 15 :: Integer)
    activityName <- sequence [elements ['a'..'z'] | _ <- [1..size]]
    timeStart <- arbitrary
    return $ Activity (activityName, timeStart)

instance Arbitrary TimeStart where
  arbitrary = do
    hour <- choose (1, 24)
    minute <- choose (1, 60)
    return $ TimeStart hour minute

instance Arbitrary Schedule where
  arbitrary = do
    size <- choose (5, 50 :: Integer)
    schedule <- sequence [(arbitrary, arbitraryActivity) | _ <- [1..size]]
    return $ Schedule schedule where
      arbitraryActivity = do
        size <- choose (5, 50 :: Integer)
        activityName <- sequence [arbitrary | _ <- [1..size]]
        return $ ActivityName activityname

第一个错误就在这一行:schedule <- sequence [(arbitrary, arbitraryActivity) | _ <- [1..size]] Expected type: Gen [Gen b0] Actual type: (Gen a0, [Gen b0])但是如何[(x,y)]正确地为这样的结构做一个任意的?

第二个错误在最后一行:return $ ActivityName activityname Data constructor not in scope: ActivityName是否不允许where像我一样在 do-notation 中使用?

标签: haskelltestingquickcheck

解决方案


当您已经拥有Arbitrary复杂类型的所有组成类型(在本例Date中为Activity、 等)的实例时,您不必做太多事情。

Arbitrary由于列表、元组等的内置实例,您可以Arbitrary像这样简单地定义组合实例:

instance Arbitrary Schedule where
  arbitrary = Schedule <$> arbitrary

编译器查看Schedule类型为 的数据构造函数[(Date, [Activity])] -> Schedule。然后,它推断右手arbitrary必须具有类型Gen (Date, [Activity]),即元组。是否Arbitrary存在实例(a, b)

是的,它确实:(Arbitrary a, Arbitrary b) => Arbitrary (a, b). 它存在 ifa是一个Arbitrary实例,如果b是。

在本例中a ~ Date,您已经为此定义了一个自定义实例。第二个元组元素有点复杂,因为它是b ~ [Activity]. 有没有Arbitrary实例[Activity]

是的,再次内置:Arbitrary a => Arbitrary [a]. 如果元素类型具有实例,则列表具有Arbitrary实例,并且同样存在用于 的自定义实例Activity


看起来您好像在明确尝试限制生成值的大小。您可以使用resize函数,而不是显式执行此操作。


推荐阅读