Odpowiedź hammar jest całkowicie wystarczająca dla problemu. Ale aby odpowiedzieć na dokładne pytanie, nie mogłem nic na to poradzić. Użyjmy forAll
.
prop_bang x = x >= 0 ==> forAll (listLongerThan x) $ \xs ->
element_at xs x == xs !! x
Teraz potrzebujemy funkcji, listLongerThan :: Int -> Gen [Int]
. Zajmuje długość x i generuje generator, który będzie tworzył listy o długości większej niż x
.
listLongerThan :: Int -> Gen [Int]
listLongerThan x = replicateM (x+1) arbitrary
To raczej prosta: po prostu skorzystać z instancji Monad z Gen
. Jeśli uruchomisz quickCheck prop_bang
, zauważysz, że zaczyna to trwać dość długo, ponieważ rozpoczyna testowanie absurdalnie długich list. Ograniczmy długość listy, aby była nieco szybsza. Ponadto teraz tylko listLongerThan
generuje listę o długości dokładnie x+1
; Załóżmy, że mieszają się nieco, ponownie wykorzystując instancji monada gen
prop_bang =
forAll smallNumber $ \x ->
forAll (listLongerThan x) $ \xs ->
element_at xs x == xs !! x
smallNumber :: Gen Int
smallNumber = fmap ((`mod` 100) . abs) arbitrary
listLongerThan :: Int -> Gen [Int]
listLongerThan x = do
y <- fmap (+1) smallNumber -- y > 0
replicateM (x+y) arbitrary
Można użyć sample smallNumber
lub sample (listLongerThan 3)
w ghci aby upewnić się, że jest generowanie prawidłowego rzeczy.
Wygląda na to, że działa idealnie, ale muszę jeszcze trochę przestudiować kod, żeby go zrozumieć. :) –
Oprócz wyszukiwania w Google, jak mogę się dowiedzieć, który pakiet zapewnia NonEmpty? –
@JoeVanDyk: To [od QuickCheck] (http://hackage.haskell.org/packages/archive/QuickCheck/2.4.1.1/doc/html/Test-QuickCheck.html#t:NonEmptyList). – hammar