2

smallcheck プロパティ ベースのテスト ライブラリを Tasty と組み合わせて使用​​する方法を見つけようとしています。

複数フィールドのレコード型で問題が発生しました: Serialtypeclass の 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」は失敗します。consNただし、関数は最大 4 つのパラメータを取るように定義されているため、このアプローチは 4 つを超えるフィールドを持つレコード タイプでは機能しません。関数が宣言されているモジュールへのリンクは次のとおりです。Test.SmallCheck.Series

次のような場合:

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'

よろしくお願いします!

ジュール

4

1 に答える 1

3

cons3SmallCheck での eg の定義方法は次のとおりです。

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(上記の定義のすべてが、データ構造の 1 つのフィールドに対応します)。

Generics コードに関しては、次のようになります。

 instance Monad m => Serial m T1

ここには何もないaので、制約は不要です (実際に問題が発生します)。

于 2013-12-14T09:37:14.897 に答える