۱۶ - ۹تست کردن نمونههای Functor با QuickCheck
با قوانینِ Functor آشنا شدیم:
fmap id = id
fmap (p . q) = (fmap p) . (fmap g)میشه اونها رو اینطوری به مشخصههای QuickCheck تبدیل کنیم:
functorIdentity :: (Functor f, Eq (f a)) =>
f a
-> Bool
functorIdentity f =
fmap id f == f
functorCompose :: (Eq (f c), Functor f) =>
(a -> b)
-> (b -> c)
-> f a
-> Bool
functorCompose f g x =
(fmap g (fmap f x)) == (fmap (g . f) x)با تأمین تایپهای معیّن، میشه این تستها رو انجام بدیم:
Prelude> :{
*Main| let f :: [Int] -> Bool
*Main| f x = functorIdentity x
*Main| :}
Prelude> quickCheck f
+++ OK, passed 100 tests.
Prelude> let c = functorCompose (+1) (*2)
Prelude> let li x = c (x :: [Int])
Prelude> quickCheck li
+++ OK, passed 100 tests.خیلی عالی.
کاری کنیم QuickCheck تابع هم ایجاد کنه
QuickCheck قابلیتِ ایجاد ِ توابع هم داره. تایپکلاسی به اسمِ CoArbitrary داره که تایپِ آرگومان تابع رو پوشش میده؛ و در مقابل، تایپکلاس Arbitrary (که بیربط هم نیست) برای تایپِ نتیجهی تابع استفاده میشه. اگه میخواین بیشتر بدونین، یه نگاه به ماژول ِ Function از کتابخونه ِ QuickCheck بندازین تا ببینید چطور از نوعدادهای که ساختِ تابع رو نشون میده، توابع ایجاد میشن.
{-# LANGUAGE ViewPatterns #-}
import Test.QuickCheck
import Test.QuickCheck.Function
functorCompose' :: (Eq (f c), Functor f) =>
f a
-> Fun a b
-> Fun b c
-> Bool
functorCompose' x (Fun _ f) (Fun _ g) =
(fmap (g . f) x) == (fmap g . fmap f $ x)اینجا چندتا کار انجام دادیم. یکی اینکه باید یه ماژول ِ جدید از QuickCheck وارد میکردیم. دیگه اینکه روی مقدارِ Fun که از QuickCheck خواستیم ایجاد کنه تطبیق الگو انجام دادیم. تایپ Fun در حقیقت حاصلضرب ِ یه جور تابع با تایپی عجیب (مختصِ خودِ QuickCheck) و یه تابعِ معمولیِ هسکله. ما فقط با بخشِ دومش کار داریم، یعنی اون تابعِ معمولی، پس با تطبیق الگو میکشیمش بیرون.
Prelude> type IntToInt = Fun Int Int
Prelude> :{
*Main| type IntFC =
*Main| [Int]
*Main| -> IntToInt
*Main| -> IntToInt
*Main| -> Bool
*Main| :}
Prelude> let fc' = functorCompose'
Prelude> quickCheck (fc' :: IntFC)
+++ OK, passed 100 tests.حواستون باشه که اون مقادیرِ Fun رو نمیشه چاپ کرد، پس verboseCheck کار نمیکنه.