Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何在应用程序上测试多态函数?_Haskell_Applicative_Quickcheck - Fatal编程技术网

Haskell 如何在应用程序上测试多态函数?

Haskell 如何在应用程序上测试多态函数?,haskell,applicative,quickcheck,Haskell,Applicative,Quickcheck,我刚刚(对于数据.Sequence) 谁应该服从 traverseWithIndex f = sequenceA . mapWithIndex f 谢天谢地,这是对mapWithIndex源代码的直接机械修改,因此我很有信心它是正确的。然而,在更复杂的情况下,需要进行彻底的测试。我正在尝试编写一个QuickCheck属性来测试这个简单的属性。显然,我不能用每个应用程序的函子来尝试它!在测试幺半群时,使用某种类型的自由幺半群(即有限列表)进行测试是很有意义的。所以,在这里用一些函子进行测试似乎是

我刚刚(对于
数据.Sequence

谁应该服从

traverseWithIndex f = sequenceA . mapWithIndex f
谢天谢地,这是对
mapWithIndex
源代码的直接机械修改,因此我很有信心它是正确的。然而,在更复杂的情况下,需要进行彻底的测试。我正在尝试编写一个QuickCheck属性来测试这个简单的属性。显然,我不能用每个
应用程序的
函子来尝试它!在测试幺半群时,使用某种类型的自由幺半群(即有限列表)进行测试是很有意义的。所以,在这里用一些函子进行测试似乎是明智的。有两个困难:

  • 如何选择合适的基函子?我大概想要一个不适用、不可遍历或任何东西的讨厌的东西,但这样的东西似乎很难处理

  • 我如何比较结果?它们将包含函数,因此它们没有
    Eq
    实例

  • 显然,我不能用每个
    应用程序的
    函子来尝试它

    我想起了这一系列博客文章,但我并不完全理解:

    我从中得到的教训是,你在野外看到的几乎每一个应用函子都是这些简单函子的合成、乘积或(受限)副产物(并非详尽无遗):

  • Const
  • Identity
  • (>)
  • 因此,虽然您不能对每个
    Applicative
    函子都进行尝试,但您可以利用QuickCheck属性中的归纳参数来获得信心,即您的函数适用于大型归纳定义的函子族。例如,您可以测试:

    • 您的函数适用于您选择的“原子”应用程序
    • 如果您的函数对函子
      f
      g
      正常工作,则它对
      Compose f g
      Product f g
      Coproduct f g
      正常工作
    我如何比较结果?它们将包含函数,因此它们没有
    Eq
    实例

    嗯,我想你可能需要看看函数相等性的快速检查测试。上一次我不得不按照这些思路做一些事情,我使用了Conal的库,它有“可以测试相等性的[t]类型的值,可能通过随机抽样。”这应该已经给了你一个想法,即使你没有函数的
    Eq
    实例,
    QuickCheck
    可能能够证明两个函数不相等。关键的是,这个实例存在:

    instance (Show a, Arbitrary a, EqProp b) => EqProp (a -> b)
    
    …任何具有
    Eq
    实例的类型都有一个平凡的
    EqProp
    实例,其中
    (=-=)=(==)

    在我看来,这意味着使用
    Coyoneda Something
    作为基本函子,并找出如何将所有小函数连接在一起。

    这里有一个部分(?)解决方案。我们要检查的主要方面是1)显然计算的值相同,2)效果的执行顺序相同。我认为以下代码是不言自明的:

    {-# LANGUAGE FlexibleInstances #-}
    module Main where
    import Control.Applicative
    import Control.Applicative.Free
    import Data.Foldable
    import Data.Functor.Identity
    import Test.QuickCheck
    import Text.Show.Functions -- for Show instance for function types
    
    data Fork a = F a | G a deriving (Eq, Show)
    
    toIdentity :: Fork a -> Identity a
    toIdentity (F a) = Identity a
    toIdentity (G a) = Identity a
    
    instance Functor Fork where
        fmap f (F a) = F (f a)
        fmap f (G a) = G (f a)
    
    instance (Arbitrary a) => Arbitrary (Fork a) where
        arbitrary = elements [F,G] <*> arbitrary
    
    instance (Arbitrary a) => Arbitrary (Ap Fork a) where
        arbitrary = oneof [Pure <$> arbitrary, 
                           Ap <$> (arbitrary :: Gen (Fork Int)) <*> arbitrary]
    
    effectOrder :: Ap Fork a -> [Fork ()]
    effectOrder (Pure _) = []
    effectOrder (Ap x f) = fmap (const ()) x : effectOrder f
    
    value :: Ap Fork a -> a
    value = runIdentity . runAp toIdentity
    
    checkApplicative :: (Eq a) => Ap Fork a -> Ap Fork a -> Bool
    checkApplicative x y = effectOrder x == effectOrder y && value x == value y
    
    succeedingExample = quickCheck (\f x -> checkApplicative 
        (traverse (f :: Int -> Ap Fork Int) (x :: [Int])) 
        (sequenceA (fmap f x)))
    
    -- note reverse
    failingExample = quickCheck (\f x -> checkApplicative 
        (traverse (f :: Int -> Ap Fork Int) (reverse x :: [Int])) 
        (sequenceA (fmap f x)))
    
    -- instance just for example, could make a more informative one
    instance Show (Ap Fork Int) where show _ = "<Ap>"
    
    -- values match ...
    betterSucceedingExample = quickCheck (\x -> 
        value (sequenceA (x :: [Ap Fork Int])) 
     == value (fmap reverse (sequenceA (reverse x))))
    
    -- but effects don't.
    betterFailingExample = quickCheck (\x -> checkApplicative 
        (sequenceA (x :: [Ap Fork Int])) 
        (fmap reverse (sequenceA (reverse x))))
    
    {-#语言灵活实例}
    模块主要在哪里
    导入控制
    导入控制.Applicative.Free
    导入数据。可折叠
    导入Data.Functor.Identity
    导入测试。快速检查
    import Text.Show.Functions--用于函数类型的Show实例
    数据分叉a=fa | ga推导(等式,显示)
    toIdentity::Fork a->Identity a
    身份(F a)=身份a
    toIdentity(ga)=恒等式a
    实例函子Fork,其中
    fmap f(FA)=f(FA)
    fmap f(GA)=G(FA)
    实例(任意a)=>任意(Fork a),其中
    任意=元素[F,G]任意
    实例(任意a)=>任意(Ap Fork a),其中
    任意的,任意的,
    Ap(任意::Gen(Fork Int))任意]
    effectOrder::Ap Fork a->[Fork()]
    有效顺序(纯=
    效应顺序(Ap x f)=fmap(const())x:effectOrder f
    值::Ap Fork a->a
    value=runIdentity。不一致性
    勾选应用::(等式a)=>Ap分叉a->Ap分叉a->Bool
    checkApplicative x y=effectOrder x==effectOrder y&&value x==value y
    succeedingExample=quickCheck(\f x->checkApplicative
    (遍历(f::Int->Ap Fork Int)(x::[Int]))
    (序列A(fmap f x)))
    --钞票背面
    failingExample=quickCheck(\f x->checkApplicative
    (遍历(f::Int->Ap Fork Int)(反向x::[Int]))
    (序列A(fmap f x)))
    --举个例子,可以做一个信息量更大的例子
    实例显示(Ap Fork Int),其中显示
    --值匹配。。。
    betterSucceedingExample=快速检查(\x->
    值(sequenceA(x::[Ap Fork Int]))
    ==值(fmap反向(序列A(反向x)))
    --但效果并不如此。
    betterFailingExample=quickCheck(\x->CheckApplication)
    (sequenceA(x::[Ap Fork Int]))
    (fmap反向(序列A(反向x)))
    
    输出如下所示:

    *Main Text.Show.Functions> succeedingExample             
    +++ OK, passed 100 tests.                                
    *Main Text.Show.Functions> failingExample                
    *** Failed! Falsifiable (after 3 tests and 2 shrinks):   
    <function>                                               
    [0,1]               
    *Main Text.Show.Functions> betterSucceedingExample
    +++ OK, passed 100 tests.
    *Main Text.Show.Functions> betterFailingExample
    *** Failed! Falsifiable (after 10 tests and 1 shrink):
    [<Ap>,<Ap>]                                     
    
    *主文本.Show.Functions>成功示例
    +++好的,通过了100次测试。
    *主文本.Show.Functions>failingExample
    ***失败了!可伪造(经过3次测试和2次收缩后):
    [0,1]               
    *Main Text.Show.Functions>betterSucceedingExample
    +++好的,通过了100次测试。
    *Main Text.Show.Functions>betterFailingExample
    ***失败了!可伪造(10次测试和1次收缩后):
    [,]                                     
    
    啊,很有趣。
    Fork
    在这里是否提供了比
    other
    更多的功能?它的种类与
    other
    不同。也就是说,您可以使用明显的(?)任意实例来执行标记为a=标记为String a的
    数据,而不是
    Fork
    。从技术上讲,我不认为这会增加歧视性权力,但它可能会使反例更容易
    *Main Text.Show.Functions> succeedingExample             
    +++ OK, passed 100 tests.                                
    *Main Text.Show.Functions> failingExample                
    *** Failed! Falsifiable (after 3 tests and 2 shrinks):   
    <function>                                               
    [0,1]               
    *Main Text.Show.Functions> betterSucceedingExample
    +++ OK, passed 100 tests.
    *Main Text.Show.Functions> betterFailingExample
    *** Failed! Falsifiable (after 10 tests and 1 shrink):
    [<Ap>,<Ap>]