Haskell 高阶类型的任意实例
Haskell Arbitrary Instance of Higher Order type
我有类型,它是 SemiGroup 的一个实例。
我想写一个quickCheck方法来确保它是正确的。
如何创建这种类型的 Arbitrary 实例?
newtype Combine a b =
Combine { unCombine :: a -> b }
instance Semigroup b => Semigroup (Combine a b) where
x <> y = Combine $ \n -> unCombine x n <> unCombine y n
instance (Q.Arbitrary a, Num a) => Q.Arbitrary (Combine a b) where
arbitrary = do
a <- Q.arbitrary
return $ Combine (\n -> Sum(n+1)) a
最小的修复方法是打开 FlexibleInstances
并写入:
instance (Q.Arbitrary a, Num a) => Q.Arbitrary (Combine a (Sum a)) where
arbitrary = do
a <- Q.arbitrary :: Q.Gen ()
return $ Combine (\n -> Sum(n+1))
然而,这有点不令人满意:我观察到 a
完全没有使用(因此必须手动给出类型签名!),并且函数的分布有点无聊,因为它 returns 概率为 1 的函数 (+1)
(直到 newtype 包装)。(也许你想要 return $ Combine (\n -> Sum (n+a))
?但即便如此,你可以用这种方式生成的函数 class 还是有点少有点无聊。我不确定你的真正意思,我不会花很长时间去推测。)
如果你想做对,你应该为每个输入产生一个随机输出。使用 universe
包非常方便:
import Data.Universe
import Data.Universe.Instances.Reverse
instance (Ord a, Finite a, Q.Arbitrary b) => Q.Arbitrary (Combine a b) where
arbitrary = Combine <$> sequenceA (const Q.arbitrary)
附带的好处是,这不需要任何扩展。但是,您应该小心选择具有小域的输入类型——Combine Bool (Sum Int)
应该没问题,甚至 Combine Word8 (Sum Word8)
,但是如果您尝试在 [=] 这样的类型上测试 属性 19=]你会后悔的!
我有类型,它是 SemiGroup 的一个实例。 我想写一个quickCheck方法来确保它是正确的。 如何创建这种类型的 Arbitrary 实例?
newtype Combine a b =
Combine { unCombine :: a -> b }
instance Semigroup b => Semigroup (Combine a b) where
x <> y = Combine $ \n -> unCombine x n <> unCombine y n
instance (Q.Arbitrary a, Num a) => Q.Arbitrary (Combine a b) where
arbitrary = do
a <- Q.arbitrary
return $ Combine (\n -> Sum(n+1)) a
最小的修复方法是打开 FlexibleInstances
并写入:
instance (Q.Arbitrary a, Num a) => Q.Arbitrary (Combine a (Sum a)) where
arbitrary = do
a <- Q.arbitrary :: Q.Gen ()
return $ Combine (\n -> Sum(n+1))
然而,这有点不令人满意:我观察到 a
完全没有使用(因此必须手动给出类型签名!),并且函数的分布有点无聊,因为它 returns 概率为 1 的函数 (+1)
(直到 newtype 包装)。(也许你想要 return $ Combine (\n -> Sum (n+a))
?但即便如此,你可以用这种方式生成的函数 class 还是有点少有点无聊。我不确定你的真正意思,我不会花很长时间去推测。)
如果你想做对,你应该为每个输入产生一个随机输出。使用 universe
包非常方便:
import Data.Universe
import Data.Universe.Instances.Reverse
instance (Ord a, Finite a, Q.Arbitrary b) => Q.Arbitrary (Combine a b) where
arbitrary = Combine <$> sequenceA (const Q.arbitrary)
附带的好处是,这不需要任何扩展。但是,您应该小心选择具有小域的输入类型——Combine Bool (Sum Int)
应该没问题,甚至 Combine Word8 (Sum Word8)
,但是如果您尝试在 [=] 这样的类型上测试 属性 19=]你会后悔的!