如何修复类列表类型的任意实例的歧义
How to fix ambiguity of an Arbitrary instance of a list-like type
考虑以下几点:
import Test.QuickCheck
import Test.QuickCheck.Checkers
import Test.QuickCheck.Classes
data List a = Nil | Cons a (List a) deriving (Eq, Show)
instance Functor List where
fmap _ Nil = Nil
fmap f (Cons a l) = Cons (f a) (fmap f l)
instance Eq a => EqProp (List a) where (=-=) = eq
genList :: Arbitrary a => Gen (List a)
genList = do
n <- choose (3 :: Int, 5)
gen <- arbitrary
elems <- vectorOf n gen
return $ build elems
where build [] = Nil
build (e:es) = Cons e (build es)
instance Arbitrary a => Arbitrary (List a) where
arbitrary = frequency [ (1, return Nil)
, (3, genList)
]
main = quickBatch $ functor (Nil :: List (Int, String, Int))
由于 genList
中的歧义,这无法编译:
• Could not deduce (Arbitrary (Gen a))
arising from a use of ‘arbitrary’
from the context: Arbitrary a
bound by the type signature for:
genList :: forall a. Arbitrary a => Gen (List a)
at reproducer.hs:13:1-38
• In a stmt of a 'do' block: gen <- arbitrary
In the expression:
do n <- choose (3 :: Int, 5)
gen <- arbitrary
elems <- vectorOf n gen
return $ build elems
In an equation for ‘genList’:
genList
= do n <- choose (3 :: Int, 5)
gen <- arbitrary
elems <- vectorOf n gen
....
where
build [] = Nil
build (e : es) = Cons e (build es)
|
16 | gen <- arbitrary
| ^^^^^^^^^
我知道我可以把genList
写成genList = Cons <$> arbitrary <*> arbitrary
,但我想知道。如何消除歧义? main
中的类型断言不是应该清除它吗?
vectorOf
期望 Gen a
。因此,GHC 会尝试为 Gen a
查找 Arbitrary
的实例,该实例不存在。
使用 vectorOf n arbitrary
或仅 vector n
。此外,建议使用 sized
让 QuickCheck 选择尺寸:
genList :: Arbitrary a => Gen (List a)
genList = sized $ \n ->
elems <- vector n
return $ build elems
where build [] = Nil
build (e:es) = Cons e (build es)
然而,在这一点上我们已经更好地使用 listOf
代替:
genList :: Arbitrary a => Gen (List a)
genList = build <$> listOf arbitary
where build = foldr Cons Nil
请注意 genList = Cons <$> arbitrary <*> arbitrary
不会生成空列表,而 foldr Cons Nil <$> listOf arbitrary
会。
考虑以下几点:
import Test.QuickCheck
import Test.QuickCheck.Checkers
import Test.QuickCheck.Classes
data List a = Nil | Cons a (List a) deriving (Eq, Show)
instance Functor List where
fmap _ Nil = Nil
fmap f (Cons a l) = Cons (f a) (fmap f l)
instance Eq a => EqProp (List a) where (=-=) = eq
genList :: Arbitrary a => Gen (List a)
genList = do
n <- choose (3 :: Int, 5)
gen <- arbitrary
elems <- vectorOf n gen
return $ build elems
where build [] = Nil
build (e:es) = Cons e (build es)
instance Arbitrary a => Arbitrary (List a) where
arbitrary = frequency [ (1, return Nil)
, (3, genList)
]
main = quickBatch $ functor (Nil :: List (Int, String, Int))
由于 genList
中的歧义,这无法编译:
• Could not deduce (Arbitrary (Gen a))
arising from a use of ‘arbitrary’
from the context: Arbitrary a
bound by the type signature for:
genList :: forall a. Arbitrary a => Gen (List a)
at reproducer.hs:13:1-38
• In a stmt of a 'do' block: gen <- arbitrary
In the expression:
do n <- choose (3 :: Int, 5)
gen <- arbitrary
elems <- vectorOf n gen
return $ build elems
In an equation for ‘genList’:
genList
= do n <- choose (3 :: Int, 5)
gen <- arbitrary
elems <- vectorOf n gen
....
where
build [] = Nil
build (e : es) = Cons e (build es)
|
16 | gen <- arbitrary
| ^^^^^^^^^
我知道我可以把genList
写成genList = Cons <$> arbitrary <*> arbitrary
,但我想知道。如何消除歧义? main
中的类型断言不是应该清除它吗?
vectorOf
期望 Gen a
。因此,GHC 会尝试为 Gen a
查找 Arbitrary
的实例,该实例不存在。
使用 vectorOf n arbitrary
或仅 vector n
。此外,建议使用 sized
让 QuickCheck 选择尺寸:
genList :: Arbitrary a => Gen (List a)
genList = sized $ \n ->
elems <- vector n
return $ build elems
where build [] = Nil
build (e:es) = Cons e (build es)
然而,在这一点上我们已经更好地使用 listOf
代替:
genList :: Arbitrary a => Gen (List a)
genList = build <$> listOf arbitary
where build = foldr Cons Nil
请注意 genList = Cons <$> arbitrary <*> arbitrary
不会生成空列表,而 foldr Cons Nil <$> listOf arbitrary
会。