为复杂类型制作任意实例

making an Arbitrary instance for a complicated type

我正在尝试使用 QuickCheck 检查我的代码,因此我需要为我的类型创建 Arbitrary 个实例。一种data Schedule复杂,不知如何正确对待。三个实例(DateActivityTimeStart)工作正常。但是最后一个例子(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 是否不允许像我那样在 do-notation 中使用 where

如果复杂类型的所有组成类型已经有 Arbitrary 个实例(在本例中为 DateActivity 等),则不必做很多。

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

instance Arbitrary Schedule where
  arbitrary = Schedule <$> arbitrary

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

是的,确实如此:(Arbitrary a, Arbitrary b) => Arbitrary (a, b)。如果 a 是一个 Arbitrary 实例,并且如果 b 是。

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

是的,又是 built-in:Arbitrary a => Arbitrary [a]。如果元素类型有实例,则列表有 Arbitrary 个实例,同样,Activity.

存在自定义实例

您似乎在明确尝试限制生成值的大小。您可以使用 resize 函数,而不是明确地执行此操作。