【问题标题】:SmallCheck: Making types instance of typeclass SerialSmallCheck:制作类型类 Serial 的类型实例
【发布时间】:2013-12-14 08:27:44
【问题描述】:

我正在尝试弄清楚如何结合使用 smallcheck 基于属性的测试库。

我在使用多字段记录类型时遇到了问题:我怎样才能创建包含Serial 类型类的超过 4 个字段成员的记录类型?

我认为这是正常的做法:

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}

import Test.Tasty
import Test.Tasty.SmallCheck
import Test.SmallCheck.Series

data T1 = T1 { p1 :: Int,
               p2 :: Char,
               p3 :: [Int]
             } deriving (Show, Eq)

instance (Monad m) => Serial m T1 where
    series = cons3 T1 

main :: IO ()
main = defaultMain tests

tests :: TestTree
tests = testGroup "Tests" [scProps]

scProps = testGroup "(checked by SmallCheck)"
  [ testProperty "Test1" prop_test1 
  ]

prop_test1 x y = x == y
               where types = (x :: T1, y :: T1)

这行得通,当然“Test1”失败了。但是,此方法不适用于具有 4 个以上字段的记录类型,因为 consN 函数仅定义为最多接受 4 个参数。这是声明函数的模块Test.SmallCheck.Serieslink

例如:

data T1 = T1 { p1 :: Int,
               p2 :: Char,
               p3 :: Int,
               p4 :: Int,
               p5 :: [Int]
             } deriving (Show, Eq)

添加到Serial的方法是什么?我尝试使用这样的泛型:

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
{-# LANGUAGE DeriveGeneric #-}

import Test.Tasty
import Test.Tasty.SmallCheck
import Test.SmallCheck.Series
import GHC.Generics

data T1 = T1 { p1 :: Int,
               p2 :: Char,
               p3 :: [Int]
             } deriving (Show, Generic)

instance Serial m a => Serial m T1

但 ghc 拒绝接受上述示例,并显示以下消息:

Variable occurs more often in a constraint than in the instance head
  in the constraint: Serial m a
  (Use -XUndecidableInstances to permit this)
  In the instance declaration for `Serial m T1'

非常感谢!

朱尔斯

【问题讨论】:

  • 对于您的«可选问题»,请创建一个新问题。
  • 嗨 Roman,非常感谢您的回答,并为图书馆付出了如此多的思考和努力——我刚刚开始学习它,但它似乎是一个很棒的工具!我移动了可选问题here
  • 此信息现在包含在documentation中。

标签: testing haskell automated-tests smallcheck


【解决方案1】:

这里是如何例如cons3 在 SmallCheck 中定义:

cons3 :: (Serial m a, Serial m b, Serial m c) =>
         (a->b->c->d) -> Series m d
cons3 f = decDepth $
  f <$> series
    <~> series
    <~> series

因此,以此类推,以下是您如何为您的类型定义任意数字的实例 字段数:

instance Monad m => Serial m T1 where
  series = decDepth $
    T1 <$> series <~> series <~> series <~> series <~> series

(上面定义中的每一个series对应你数据的一个字段 结构)。

关于您的泛型代码,它应该如下所示:

 instance Monad m => Serial m T1

这里没有a,所以你的约束是多余的(实际上会导致问题)。

【讨论】:

    猜你喜欢
    • 2021-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-15
    • 2014-10-02
    • 1970-01-01
    相关资源
    最近更新 更多