Haskell 使用快速检查的上下文敏感生成

Haskell 使用快速检查的上下文敏感生成,haskell,quickcheck,Haskell,Quickcheck,我想根据某种“上下文”生成随机术语,我想知道是否可以使用快速检查。基本上,我希望传递一个附加的数据类型,以便任意函数可以基于附加参数生成术语。。。这可以通过quickcheck实现,还是我应该编写自己对Gen的定义?从任意中实现这一点是可能的,尽管不是很明智。但是,如果您跳出任意,您可以直接传递一个额外的参数 -- do whatever you want inside the implementation of these two chooseIntRange :: Context ->

我想根据某种“上下文”生成随机术语,我想知道是否可以使用快速检查。基本上,我希望传递一个附加的数据类型,以便任意函数可以基于附加参数生成术语。。。这可以通过quickcheck实现,还是我应该编写自己对Gen的定义?

任意
中实现这一点是可能的,尽管不是很明智。但是,如果您跳出
任意
,您可以直接传递一个额外的参数

-- do whatever you want inside the implementation of these two
chooseIntRange :: Context -> Int
updateContext :: Int -> Context -> Context

arbitraryIntWithContext :: Context -> Gen (Context, Int)
arbitraryIntWithContext ctx = do
    n <- choose (0, chooseIntRange ctx)
    return (n, updateContext n ctx)

虽然Daniel Wagner为QuickCheck(+1)提供了一个很好的答案,但它也突出了QuickCheck的一个弱点。在快速检查中,可以使用
任意
的实例编写属性,但由于其设计,
任意
不是一元的

另一方面,Daniel Wagner分享的解决方法是
Gen
是一元的,因此您可以使用
do
符号编写上下文相关的代码。缺点是,虽然您可以将
gena
转换为
任意a
,但您必须提供自定义
收缩
实现,或者放弃收缩

用于基于属性的测试的替代库的设计方式是,属性本身是一元的,这意味着您可以编写整个属性,只需在测试代码本身中嵌入特定于上下文的特定值生成(包括收缩):

propWithContext :: Property
propWithContext = property $ do
  ctx <- forAll genContext
  n <- forAll $ Gen.integral $ Range.linear 0 $ chooseIntRange ctx
  let ctx' = updateContext n ctx

  -- Exercise SUT and verify result here...

谢谢你的回答!我可以看到如何将其更改为使用多态类型,并由此创建ContextArbitral类型类
propWithContext :: Property
propWithContext = property $ do
  ctx <- forAll genContext
  n <- forAll $ Gen.integral $ Range.linear 0 $ chooseIntRange ctx
  let ctx' = updateContext n ctx

  -- Exercise SUT and verify result here...
genContext :: MonadGen m => m Context