コメントアウトしcheck2
てGHCiにタイプを尋ねることから始めましょうprop_2
:
*Main> :t prop_2
prop_2 :: Eq a => [a] -> Property
さて、あなたが書いたようにprop_2
、それは等式クラスにある任意の要素タイプのリストに対して機能します。
prop_2
ここで、関数に渡しquickCheck
ます。次のタイプを見てみましょうquickCheck
:
*Main> :t quickCheck
quickCheck :: Testable prop => prop -> IO ()
この関数は実際には非常に一般的なタイプです。クラスにあるものなら何でも動作しTestable
ます。Testable
では、このクラスはどのように機能しますか?ここには、いくつかの基本インスタンスがあります。次に例を示します。
instance Testable Bool
instance Testable Property -- this is a simplification, but it's more or less true
これらのインスタンスはQuickCheckライブラリで定義されており、定数ブール値とタイプPropertyの要素をクイックチェックできることを示しています。
現在、入力に依存しないプロパティのテストは特に興味深いものではありません。興味深い例はこれです:
instance (Arbitrary a, Show a, Testable prop) => Testable (a -> prop)
Arbitrary a
つまり、特定のタイプのランダムな値を生成する方法( )とそのタイプの値を表示する方法()を知っている場合は、そのタイプからすでにテスト可能なタイプまでShow a
関数をテストすることもできます。a
prop
なんで?それがQuickCheckの動作方法だからです。このような状況では、QuickCheckはArbitrary
インスタンスを調べて、タイプのランダムなテストケースを考え出しa
、それぞれに関数を適用して、結果が肯定的かどうかを確認します。いずれかのテストが失敗すると、テストの失敗を通知するメッセージが出力され、テストケースが出力されます(そのため、Show
要件もあります)。
さて、私たちの状況では、これはクイックチェックができるはずであることを意味しますprop_2
:それは結果としてProperty
。重要なことは、関数の引数(保持[a]
されている限りの型)がクラスのメンバーであり、クラスのメンバーであるということです。Eq a
Arbitrary
Show
ここで、エラーの原因に到達します。入手可能な情報は、その結論を出すのに十分ではありません。最初に言ったように、prop_2
同等性を認めるあらゆる要素タイプのリストに対して機能します。これらすべてのタイプがとであるという組み込みのルールはありませArbitrary
んShow
。しかし、あったとしても、QuickCheckはどのようなリストを生成する必要がありますか?ブール値のリスト、ユニットタイプのリスト、関数のリスト、文字のリスト、整数のリストを生成する必要がありますか?非常に多くのオプションがあり、要素タイプの選択は、バグを見つけるかどうかに影響を与える可能性があります。(GHCが1つの要素だけでユニットタイプを選択することを考慮して()
ください。そうすると、プロパティは任意の2つの関数p
とq
入力リストが目的のスワッピングプロパティを持っているかどうかに関係なく、入力リストの長さを保持します。)
これが、リストに使用する要素タイプを解決できるように、GHCに追加のタイプ情報を提供する必要がある理由です。そうすることは十分に簡単です。prop_2
自分自身に注釈を付けることができます。
prop_2 :: [Integer] -> Property
または、それを望まない場合(再実装せずにさまざまな種類のリストでテストを実行したい場合があるためprop_2
)、呼び出し時に型アノテーションを追加できますquickCheck
。
check2 = quickCheck (prop_2 :: [Integer] -> Property)
これでコードがコンパイルされ、次のコマンドを実行できますcheck2
。
Main*> check2
+++ OK, passed 100 tests.