2016-04-05 4 views
1

Ich möchte SmallCheck verwenden, um meinen Code zu testen. Ich habe es geschafft, willkürliche Listen von Paaren von Ints zu erzeugen, aber das ist nicht das, was mein Typ enthalten sollte. Die Liste stellt eine Reihe von Bereichen dar, wobei [1,3),[4,6) als [(1,3),(4,6)] codiert/gespeichert wird.SmallCheck generiert Daten, die Invarianten erfüllen

Dies sind die Invarianten für die normalisierte Form meiner Bereiche:

fst a < snd a 
snd a < fst b where a is before b in the list 

Ich möchte dies SmallCheck kommunizieren, so dass es viele Werte nicht erzeugen, die ich wegwerfen, weil sie aren‘ t meine Invarianten zu befriedigen, aber vielleicht ist das nicht möglich.

Wie kann ich Listen erstellen, die meine Invarianten erfüllen?

+0

können Sie ein zufälliges '[NonNegative Int]' mit gerader Länge erzeugen und dann eine 'scan (+) 0' und eine Hilfsfunktion verwenden, um sie zu paaren. – epsilonhalbe

+0

ahh und pass auf 'Int'-Überläufe ;-) – epsilonhalbe

+0

@epsilonhalbe, das ist schlau, aber Testeigenschaften sollten normalerweise offensichtlich korrekter/vollständiger sein. – dfeuer

Antwort

3

Bevorzugung von anwendungsspezifischen Typen gegenüber integrierten Typen (Int, Liste). Dies ist nicht nur ein Ratschlag für SmallCheck, sondern für jede Software in jeder Sprache.

data Interval = Interval (Int,Int) 
data Domain = Domain [Interval] 

Schreiben Sie intelligente Konstruktoren, die Ihre Invarianten erzwingen.

interval :: Int -> Int -> Interval 
interval x y = Interval (min x y, max x y) -- if you want this 

domain :: [Interval] -> Domain 
domain ints = Domain ... (something that sorts intervals, and perhaps merges them) 

Verwenden Sie diese dann, um serielle Instanzen zu erstellen.

+0

Ich denke, das Sortieren/Zusammenführen ist ein unnötiger Overhead, verglichen mit dem Erzeugen von ihnen selbst, wenn sie nur für Testeigenschaften erzeugt werden – epsilonhalbe

0

Ich stimme zu, dass dieses Problem besser mit benutzerdefinierten Typen gelöst wird.

Ich nehme an, Sie schreiben einen Algorithmus, der eine Eigenschaft für disjunkte halboffene Intervalle hat, die in aufsteigender Reihenfolge sortiert sind, dann liefert das folgende Serial Instanzen.

Ich entschied mich, Interval und AscDisjIntervals verschiedene Generatoren zu geben, anstatt eine in Bezug auf die andere zu implementieren.

Der Algorithmus für AscDisjIntervals ist, wie ich bereits in dem Kommentar schrieb

  • eine Liste von nicht-negativen Integer s zu erzeugen (dies ist Int Überlauf zu vermeiden)
  • diese ganzen Zahlen Summieren (dies behauptet eine aufsteigende Reihenfolge aller
  • Paare aus dieser Liste Werte zu erzeugen (Verwerfen des letzten Einzelelement, wenn die Liste eine ungerade Anzahl von Elementen hat)

Intervals.hs

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} 
module Intervals where 

newtype Interval = I (Integer,Integer) deriving(Eq) 

instance Show Interval where 
    show (I (a,b)) = "["++show a ++ ", "++ show b ++ "]" 

instance Monad m => Serial m Interval where 
    series = let a_b a b = I (getNonNegative $ min a b , getNonNegative $ max a b) 
      in cons2 a_b 

newtype AscDisjIntervals = ADI [Interval] deriving (Eq) 

instance Show AscDisjIntervals where 
    show (ADI x) = "|- "++ (unwords $ map show x) ++ " ->" 

instance Monad m => Serial m AscDisjIntervals where 
    series = cons1 aux1 

aux1 :: [NonNegative Int] -> AscDisjIntervals 
aux1 xx = ADI . generator . tail $ scanl (+) 0 xx 
    where generator [] = [] 
     generator (_:[]) = [] 
     generator (x:y:xs) = let i = I (getNonNegative x ,getNonNegative y) 
         in i:generator xs 

Hinweis: Ich habe nur das Programm zusammengestellt und getestet wurden keine Eigenschaften.

Verwandte Themen