QuickCheck如何检测数据类型?

如果我们定义这样的函数

fun :: Int -> Property

然后运行

quickCheck fun

quickCheck开始生成Int类型的随机数据。问题是quickCheck如何检测fun的参数数据类型是Int而不是其他任何数据类型?如果我让这个问题更笼统,我应该问我们是否有一个像fun这样的函数

fun :: datatype_1 -> datatype_2 -> ... -> datatype_n -> Property

quickCheck如何检测每个单独的数据类型_1,数据类型_2,...和数据类型_n的类型?以及它如何检测功能fun需要多少个参数?

wangyan_world 回答:QuickCheck如何检测数据类型?

大致上,这就是类型类的工作方式。一个人可以宣布

class C a where
   foo :: a -> Bool

然后

instance C (Int -> Bool) where
   foo f = f 42
instance C (String -> Bool) where
   foo f = f "hello"
instance C (String -> [Int]) where
   foo f = sum (f "hello") > 42

以此类推。

这显然可以使foo“检测”其自变量f的类型并采取相应的措施。实际上,发生的事情是Haskell执行类型推断,在此期间在编译时选择了适当的实例。在运行时,不会发生“类型检测”;实际上,类型在编译后会被擦除,并且在运行时没有类型信息可用,因此将无法检测到f属于哪个类型。

当然,实际的QuickCheck机制要复杂得多。为了处理带有任意数量参数的函数,可以使用一组“递归” instance,可以说每个“递归调用”都处理每个参数。这是一种相当棘手的技术,也用在printf和其他“可变”函数中。如果您不熟悉类型类,建议您不要从这种复杂的技巧开始学习它们。

,

聚会晚了一点,但是this is the instance在当前实现中正在寻找。

instance (Arbitrary a,Show a,Testable prop) => Testable (a -> prop) where
  property f =
    propertyForAllShrinkShow arbitrary shrink (return . show) f
  propertyForAllShrinkShow gen shr shw f =
    -- gen :: Gen b,shr :: b -> [b],f :: b -> a -> prop
    -- Idea: Generate and shrink (b,a) as a pair
    propertyForAllShrinkShow
      (liftM2 (,) gen arbitrary)
      (liftShrink2 shr shrink)
      (\(x,y) -> shw x ++ [show y])
      (uncurry f)

正如@chi正确指出的,这里有递归发生。递归调用是propertyForAllShrinkShow调用propertyForAllShrinkShow,并且通过调用uncurry,形式为a -> b -> c -> Bool的属性将变成(a,b) -> c -> Bool。由于(a,b)instance的{​​{1}},因此Arbitrary (a,b)是有效的任意值,Testable的相同实例将再次运行,其中propc -> Bool 。然后,将再次与((a,b),c运行,然后prop将只是Bool。此时,将使用默认的propertyForAllShrinkShow启动Bool instance of Testable,它创建了f x的实际应用程序。因此,另一种说法是,快速检查会同时生成一个任意元组的所有值,并使用instance的{​​{1}}中的递归构造元组。

本文链接:https://www.f2er.com/3144896.html

大家都在问