gpt4 book ai didi

f# - FsCheck:覆盖类型的生成器,但仅在单个父生成器的上下文中

转载 作者:行者123 更新时间:2023-12-05 02:28:38 26 4
gpt4 key购买 nike

我似乎经常遇到这样的情况,我想生成一些复杂的结构,但生成的成员类型的特殊变体却不同。

例如,考虑这棵树

type Tree<'LeafData,'INodeData> =
| LeafNode of 'LeafData
| InternalNode of 'INodeData * Tree<'LeafData,'INodeData> list

我想生成这样的案例

  • 没有一个内部节点是无 child 的
  • 没有叶型节点
  • 只使用了有限的叶子类型子集

如果我覆盖相应子类型的所有生成,这些操作很简单。问题是似乎register本质上是一个线程级操作,没有 gen-local 替代方案。

比如我想要的样子

let limitedLeafs =
gen {
let leafGen = Arb.generate<LeafType> |> Gen.filter isAllowedLeaf
do! registerContextualArb (leafGen |> Arb.fromGen)
return! Arb.generate<Tree<NodeType, LeafType>>
}

这个 Tree 示例特别可以解决一些创意类型的改组问题,但这并不总是可行的。

也可以使用某种强制执行假设的递归映射,但如果上述可能的话,这似乎相对复杂。不过,我可能误解了 FsCheck 生成器的性质。

有谁知道如何完成这种 gen-local override?

最佳答案

此处有几个选项 - 我假设您使用的是 FsCheck 2.x,但继续滚动以在 FsCheck 3 中找到一个选项。

第一个是最自然但工作量更大的方法,即将生成器显式分解为您需要的级别,然后再次将 humpty dumpty 组合在一起。即不要太依赖基于类型的生成器推导 - 如果我正确理解你的示例,那将意味着实现 recursive generator - 依靠Arb.generate<LeafType>对于通用类型。

第二个选项 - Config 有一个 Arbitrary您可以用来覆盖 Arbitrary 的字段实例。即使被覆盖的类型是自动生成的类型的一部分,这些覆盖也会生效。因此,作为草图,您可以尝试:

Check.One ({Config.Quick with Arbitrary = [| typeof<MyLeafArbitrary>) |]) (fun safeTree -> ...)

More extensive example它使用 FsCheck.Xunit 的 PropertyAttribute但是原理是一样的,设置在Config上相反。

最后的选择! :) 在 FsCheck 3(预发行版)中,您可以通过一个新的(尚未记录的)概念进行配置 ArbMap这使得映射从 type 到 Arbitrary instance explicit,而不是 2.x 中的这种静态全局废话(当然是我的不好。当时似乎是个好主意。)实现是 here这可能不会告诉你那么多 - 这个想法是你把一个 ArbMap实例一起包含子部分的“安全”生成器,然后你ArbMap.mergeWith ArbMap.defaults 的安全 map (因此在生成的 ArbMap 中用您的安全生成器覆盖默认生成器)然后您使用 ArbMap.arbitraryArbMap.generate生成的 map 。

抱歉冗长的解释 - 但总而言之,这应该给你两全其美 - 你可以在 FsCheck 中重用通用联合类型生成器,同时在该上下文中手术覆盖某些类型。

关于f# - FsCheck:覆盖类型的生成器,但仅在单个父生成器的上下文中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72567119/

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