2013-05-08 4 views
33

ich eine einfache Typdefinition haben:Wie beliebige Instanzen eines einfachen Typs für Quick Check erzeugen

data Cell = Cell { 
    x  :: Int, 
    y  :: Int 
    } deriving (Show) 

ich nicht Cell als Eingabe in einem Quick Check-Eigenschaft verwenden können, vermutlich, weil Quick Check nicht weiß, wie um Zellenwerte zu generieren.

Mein Verständnis ist, dass ich Cell eine Instanz der Arbitrary Typklasse machen muss.

Wie mache ich das zum Beispiel, wenn ich möchte, dass Cell mit zufälligen positiven Werten für x und y erzeugt wird?

Antwort

45

Das Schreiben einer Instanz von Arbitrary für Ihren Datentyp ist einfach. Sie müssen nur die arbitrary Funktion implementieren, die eine Gen Cell zurückgeben sollte. Der einfachste Weg, dies zu tun ist, um die Verwendung bestehender Arbitrary Instanzen zu machen und beachten Sie auch, dass Gen eine Monade ist, so können wir do -Notation verwenden:

instance Arbitrary Cell where 
    arbitrary = do 
    Positive x <- arbitrary 
    Positive y <- arbitrary 
    return $ Cell x y 

Alternativ-Generatoren können oft elegant Operatoren geschrieben werden von Control.Applicative : Hier

instance Arbitrary Cell where 
    arbitrary = Cell <$> pos <*> pos 
    where pos = getPositive <$> arbitrary -- getPositive requires QC >= 2.5 

, ich habe auch den Positive Modifikator von Test.QuickCheck.Modifiers vorgenommen, um sicherzustellen, dass wir nur positive ganze Zahlen erzeugen.

Um komplexere Generatoren zu schreiben, werfen Sie einen Blick auf die verschiedenen Generatoren von Test.QuickCheck.Gen.

+2

Dies ist, wo ich * wirklich * würde gerne anstelle Applicative Syntax verwenden. –

+3

Denken Sie auch darüber nach, eine Implementierung für 'shrink' zu schreiben. Weniger wichtig vielleicht, aber spart für manche Fälle so viel Aufwand. –

15

Sie können eine Arbitrary Instanz, die das gleiche mit TemplateHaskell und derive Paket erzeugen:

import Data.DeriveTH 

derive makeArbitrary ''Cell 
+5

Sie sollten erwähnen, woher Data.DeriveTH kommt. –