Myślę, że to z powodu ograniczeń technicznych, ponieważ obecnie ocenić Testable
z biblioteką Test.QuickCheck
, trzeba użyć jednej z quickCheck*
funkcji, które są bardzo IO
-centric. Dzieje się tak, ponieważ właściwości testu QuickCheck Testable
poprzez losowe generowanie możliwych danych wejściowych (domyślnie 100), próbując znaleźć counterexample, co świadczy o fałszywej właściwości. Jeśli takie dane wejściowe nie zostaną znalezione, zakłada się, że właściwość jest prawdziwa (chociaż niekoniecznie jest to prawda, może to być kontrprzykład, który nie był testowany). Aby móc generować losowe dane wejściowe w Haskell, trzymamy się monady IO
.
Należy zauważyć, że chociaż assert
został zdefiniowany w taki ogólny sposób, jest używany przez cały papier tylko z Bool
. Tak więc autor biblioteki (ten sam w dokumencie) wolał poświęcić ogólny parametr Testable
dla zwykłego Bool
, aby nie wymuszać żadnej monady w tym momencie.
I widzimy, że oni nawet napisane oryginalny podpis jako komentarz w source code:
-- assert :: Testable prop => prop -> PropertyM m()
Należy również zauważyć, że pomimo faktu, że stop
funkcja ma podobny podpis:
stop :: (Testable prop, Monad m) => prop -> PropertyM m a
Jest to , a nie takie samo, jak funkcja assert
w dokumencie, ponieważ pierwsza z nich będzie zatrzymywać obliczenia w b W innych przypadkach warunkiem jest True
lub False
. Z drugiej strony, assert
zatrzyma tylko wyliczenie jeśli warunek jest False
:
⟦dochodzić Prawdziwa »P⟧ = ⟦p⟧
⟦dochodzić Fałsz» P⟧ = {return false}
Możemy jednak łatwo napisać IO
wersję funkcji assert
z papieru:
import Control.Monad
import Control.Monad.Trans
import Test.QuickCheck
import Test.QuickCheck.Monadic
import Test.QuickCheck.Property
import Test.QuickCheck.Test
assertIO :: Testable prop => prop -> PropertyM IO()
assertIO p = do r <- liftIO $ quickCheckWithResult stdArgs{chatty = False} p
unless (isSuccess r) $ fail "Assertion failed"
A teraz możemy wykonać test, aby zobaczyć różnice między assertIO
i stop
:
prop_assert :: Property
prop_assert = monadicIO $ do assertIO succeeded
assertIO failed
prop_stop :: Property
prop_stop = monadicIO $ do stop succeeded
stop failed
main :: IO()
main = do putStrLn "prop_assert:"
quickCheck prop_assert
putStrLn "prop_stop:"
quickCheck prop_stop
succeeded
i failed
można zastąpić True
i False
, odpowiednio. Chodziło o pokazanie, że teraz nie jesteśmy ograniczeni do Bool
, zamiast tego możemy użyć dowolnego Testable
.
a wyjście jest:
prop_assert:
*** nie powiodło się! Asercja nie powiodła się (po 1 teście):
prop_stop:
+++ OK, zaliczyła 100 testów.
Jak widać, mimo że pierwsza assertIO
udało prop_assert
powiodło się z powodu drugiego assertIO
. Z drugiej strony test zakończył się pomyślnie, ponieważ pierwsze stop
powiodło się i obliczenia zostały zatrzymane w tym momencie, nie testując drugiego stop
.
Być może komentarze ze źródła będą pomocne: [(link)] (https://github.com/nick8325/quickcheck/blob/master/Test/QuickCheck/Monadic.hs#L118-126). Interesujące, że komentarz do 'assert' ma sig papieru, a także' stop' w zasadzie ma to samo znaczenie. – ErikR