gpt4 book ai didi

haskell - 在 QuickCheck 中缩小记录的惯用方法

转载 作者:行者123 更新时间:2023-12-04 00:56:41 24 4
gpt4 key购买 nike

假设我有一个记录类型:

data Foo = Foo {x, y, z :: Integer}

编写 Arbitrary 实例的一种简洁方式使用 Control.Applicative,如下所示:
instance Arbitrary Foo where
arbitrary = Foo <$> arbitrary <*> arbitrary <*> arbitrary
shrink f = Foo <$> shrink (x f) <*> shrink (y f) <*> shrink (z f)

因此, Foo 的收缩列表是其成员的所有收缩的笛卡尔积。

但是,如果其中一个收缩返回 [ ] 那么整个 Foo 将不会收缩。所以这行不通。

我可以尝试通过在收缩列表中包含原始值来保存它:
   shrink f = Foo <$> ((x f) : shrink (x f)) <*> ... {and so on}.

但是现在shrink (Foo 0 0 0) 将返回[Foo 0 0 0],这意味着收缩永远不会终止。所以这也行不通。

看起来这里应该使用除了 <*> 以外的其他东西,但我看不到是什么。

最佳答案

如果你想要一个可以在一个位置收缩的应用仿函数,你可能会喜欢我刚刚创建的这个函数,它可以精确地抓取那个痒:

data ShrinkOne a = ShrinkOne a [a]

instance Functor ShrinkOne where
fmap f (ShrinkOne o s) = ShrinkOne (f o) (map f s)

instance Applicative ShrinkOne where
pure x = ShrinkOne x []
ShrinkOne f fs <*> ShrinkOne x xs = ShrinkOne (f x) (map ($x) fs ++ map f xs)

shrinkOne :: Arbitrary a => a -> ShrinkOne a
shrinkOne x = ShrinkOne x (shrink x)

unShrinkOne :: ShrinkOne t -> [t]
unShrinkOne (ShrinkOne _ xs) = xs

我在看起来像这样的代码中使用它,以缩小元组的左元素或元组右元素的字段之一:
shrink (tss,m) = unShrinkOne $
((,) <$> shrinkOne tss <*> traverse shrinkOne m)

到目前为止效果很好!

事实上,它很好用,我把它上传为 a hackage package .

关于haskell - 在 QuickCheck 中缩小记录的惯用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14006005/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com