【问题标题】:QuickCheck tests for dependent types依赖类型的 QuickCheck 测试
【发布时间】:2014-06-07 04:46:58
【问题描述】:

我正在编写依赖类型的VectorMatrix 数据类型。

data Vector n e where
  EmptyVector :: Vector Zero e
  (:>)        :: e -> Vector n e -> Vector (Succ n) e

deriving instance Eq e => Eq (Vector n e)

infixr :>

data Matrix r c e where
  EmptyMatrix :: Matrix Zero c e
  (:/)        :: Vector c e -> Matrix r c e -> Matrix (Succ r) c e

deriving instance Eq e => Eq (Matrix r c e)

infixr :/

它们取决于自然数,也是一种类型。

data Natural where
    Zero :: Natural
    Succ :: Natural -> Natural

我写了一个函数来计算矩阵的列数。

columns :: Matrix r c e -> Int
columns m = Fold.foldr (\_ n -> 1 + n) 0 $ getRow 0 m

getRow :: Int -> Matrix r c e -> Vector c e
getRow 0 (v :/ _)    = v
getRow i (_ :/ m)    = getRow (i - 1) m
getRow _ EmptyMatrix = error "Cannot getRow from EmptyMatrix."

我现在想使用 QuickCheck 测试 columns 函数。

为此,我必须将MatrixVector 声明为QuickCheck 提供的Arbitrary 类型类的实例。

但是,我不知道该怎么做。

  • 我的数据是依赖类型的这一事实是否会影响我编写这些实例的方式?

  • 如何生成任意长度的矩阵,确保它们与定义匹配(例如,(Succ (Succ r)) 将有两行)?

【问题讨论】:

    标签: haskell quickcheck


    【解决方案1】:

    您可以编写一个在编译时已知的特定长度的实例:

    instance Arbitrary (Vector Zero e) where
        arbitrary = return EmptyVector
    
    instance (Arbitrary e, Arbitrary (Vector n e))
        => Arbitrary (Vector (Succ n) e) where
        arbitrary = do
          e <- arbitrary
          es <- arbitrary
          return (e :> es)
    

    上面的实例本身并不是很有用,除非你想写 您想尝试的每个长度的一个表达式(或获取 template-haskell 到 生成这些表达式)。一种获取Int 来决定n 类型的方法 应该是将n隐藏在一个存在中:

    data BoxM e where
        BoxM :: Arbitrary (Vector c e) => Matrix r c e -> BoxM e
    
    data Box e where Box :: Arbitrary (Vector c e) => Vector c e -> Box e
    
    addRow :: Gen e -> BoxM e -> Gen (BoxM e)
    addRow mkE (BoxM es) = do
        e <- mkE
        return $ BoxM (e :/ es)
    
    firstRow :: Arbitrary a => [a] -> BoxM a
    firstRow es = case foldr (\e (Box es) -> Box (e :> es)) (Box EmptyVector) es of
        Box v -> BoxM (v :/ EmptyMatrix)
    

    使用 addRow 和 firstRow,编写一个 mkBoxM :: Int -&gt; Int -&gt; Gen (BoxM Int),然后像这样使用它:

    forAll (choose (0,3)) $ \n -> forAll (choose (0,3)) $ \m -> do
          BoxM matrix <- mkBoxM n m
          return $ columns matrix == m -- or whatever actually makes sense
    

    【讨论】:

    • 谢谢!这很有帮助。
    猜你喜欢
    • 1970-01-01
    • 2012-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-20
    • 2018-12-27
    • 1970-01-01
    相关资源
    最近更新 更多