2014-06-07 32 views
5

Bağımlı olarak yazılan Vector ve Matrix veri türlerini yazıyorum.Bağımlı türler için QuickCheck testleri

data Vector n e where 
    EmptyVector :: Vector Zero e 
    (:>)  :: e -> Vector n e -> Vector (Succ n) e 

deriving instance Eq e => Eq (Vector n e) 

infixr :> 

data Matrix r c e where 
    EmptyMatrix :: Matrix Zero c e 
    (:/)  :: Vector c e -> Matrix r c e -> Matrix (Succ r) c e 

deriving instance Eq e => Eq (Matrix r c e) 

infixr :/ 

Ayrıca, doğal sayılara da bağlıdırlar.

data Natural where 
    Zero :: Natural 
    Succ :: Natural -> Natural 

Matristeki sütun sayısını hesaplamak için bir işlev yazdım.

columns :: Matrix r c e -> Int 
columns m = Fold.foldr (\_ n -> 1 + n) 0 $ getRow 0 m 

getRow :: Int -> Matrix r c e -> Vector c e 
getRow 0 (v :/ _) = v 
getRow i (_ :/ m) = getRow (i - 1) m 
getRow _ EmptyMatrix = error "Cannot getRow from EmptyMatrix." 

şimdi QuickCheck kullanarak columns işlevini test etmek istiyorum.

Bunu yapmak için, QuickCheck tarafından sağlanan Arbitrary tür sınıfının örnekleri olarak Matrix ve Vector bildirmeliyim. Bununla birlikte, bunun nasıl yapılacağı konusunda bir kayıp yapıyorum.

  • Verilerimin isteğe bağlı olarak yazılması, bu örnekleri nasıl yazdığımı etkiler mi?

  • Rasgele uzunluk matrislerini, tanımlarıyla eşleşmelerini sağlayarak nasıl oluştururum (örn. (Succ (Succ r)) iki satıra sahip olur)? Yukarıdaki örnekler her biri için bir ifade yazmak istiyorum sürece çok yararlı değildir kendileri tarafından

    instance Arbitrary (Vector Zero e) where 
        arbitrary = return EmptyVector 
    
    instance (Arbitrary e, Arbitrary (Vector n e)) 
        => Arbitrary (Vector (Succ n) e) where 
        arbitrary = do 
         e <- arbitrary 
         es <- arbitrary 
         return (e :> es) 
    

    :

cevap

6

Sen derleme sırasında bilinen belirli bir uzunluk için bir çok örneğini yazabilirsiniz Denemek istediğiniz uzunluk (veya şablon-haskell'i bu ifadeleri oluşturun). Tek yönlü bir Intn olmalıdır tip bir varoluşsal içinde n gizlemeye ne karar almak için:

AddRow ve firstRow ile
data BoxM e where 
    BoxM :: Arbitrary (Vector c e) => Matrix r c e -> BoxM e 

data Box e where Box :: Arbitrary (Vector c e) => Vector c e -> Box e 

addRow :: Gen e -> BoxM e -> Gen (BoxM e) 
addRow mkE (BoxM es) = do 
    e <- mkE 
    return $ BoxM (e :/ es) 

firstRow :: Arbitrary a => [a] -> BoxM a 
firstRow es = case foldr (\e (Box es) -> Box (e :> es)) (Box EmptyVector) es of 
    Box v -> BoxM (v :/ EmptyMatrix) 

, bir mkBoxM :: Int -> Int -> Gen (BoxM Int) yazmak için oldukça açık olmalı ve ardından kullanmak bunun gibi:

forAll (choose (0,3)) $ \n -> forAll (choose (0,3)) $ \m -> do 
     BoxM matrix <- mkBoxM n m 
     return $ columns matrix == m -- or whatever actually makes sense 
+0

Teşekkür ederiz! Bu çok yardımcı oldu. – sdasdadas