c# - 具有成对限制的列表的 FsCheck 生成器 (C#)
问题描述
在 C# 中使用 FsCheck,我需要生成一个值列表,其中某些值可能不会相邻出现。这是词法分析器的标记列表。例如,我不需要生成两个相邻的标识符,或者一个关键字旁边的标识符,因为当它们变成字符串时,词法分析器会将它们视为一个标记。我不能简单地做这样的事情:
Gen.ListOf(Gen.Elements("fizz", "buzz", "bazz", "+", " ", "if")).Where(list => ...);
在一个合理长度的列表中,很可能有两个不应该相邻的标记。因此过滤器会丢弃太多的值,生成会很慢。我考虑过添加或删除标记来尝试修复列表,但这似乎非常复杂,我担心它会生成太短或太长的列表。
我想要做的是“一次一个元素”生成列表。所以我会随机选择长度,然后随机选择每个元素是否允许跟随前面的元素,直到我得到完整的列表。这似乎应该是递归可行的,但我不知道如何用生成器组合器来表达它。有没有办法做到这一点?我希望我可以编写一个任意的 lambda,它可以直接调用其中的生成器,而不需要编写它们。这样的事情可能吗?
注意:我已经简化了示例。令牌生成要复杂得多。
解决方案
假设你有identifier
两种keyword
类型Gen<string>
,你可以做类似 (C#-y 伪代码)
var any = Gen.Elements (new[] {identifier, keyword});
Gen<ImmutableList<string>> Generate(int length, Gen<ImmutableList<string>> soFar) {
if (length == 0) return soFar;
var result = soFar.SelectMany(l => {
// after a keyword anything goes, after an identifier must follow a keyword
var noId = ... // check what last token in l is
var next = noId ? keyword : any;
return next.SelectMany(n => l.Add(n));
});
return Generate(length-1, result);
}
您还可以创建一个枚举值 + 字符串列表,以便枚举值定义您正在生成的令牌类型(从您刚刚生成的文本中找出令牌的类型对我来说似乎有点奇怪......这听起来也很奇怪就像它正是您要测试的代码一样)。
一般来说,我可能会建议一种不同的方法,这取决于你有多少令牌以及所有的约束是什么。在这种情况下,通常更容易定义一些“模式”,即合法的令牌列表,您可以一个接一个地串而不中断(太多,可能在工作后进行另一个过滤器)。一个例子(在 F# 中)在这里:https ://github.com/fsprojects/fantomas/blob/master/src/Fantomas.Tests/FormattingPropertyTests.fs
这些模式通常最终成为您的语法或句法树,因此基本结构应该很简单。
推荐阅读
- git - 执行 git clone 时“过滤内容”是什么意思?
- php - 在 Woocommerce 中检索产品图库图像缩略图
- php - 当特定产品在 Woocommerce 的购物车中时,将加拿大从国家/地区列表中删除
- r - 当我尝试运行 for 循环时,为什么 R 会删除我文件中的所有信息?
- javascript - 停止输入重新渲染 onChange
- css - CSS中的自动幻灯片过渡循环
- ssl - 如果是自签名证书,浏览器是否不验证数字签名
- c# - 如何将 C++ 控制台参数发送到 C# DLL
- r - 基于多个范围合并
- reverse-engineering - 缓冲区溢出 - 没有足够的空间用于 shellcode