F# 为相同长度的整数列表对指定一个任意值
我需要一些帮助来做这个关于f#中的生成器的练习 功能F# 为相同长度的整数列表对指定一个任意值,f#,generator,fscheck,F#,Generator,Fscheck,我需要一些帮助来做这个关于f#中的生成器的练习 功能 List.zip : ('a list -> 'b list -> ('a * 'b) list) 及 在对列表进行操作的条件下,它们彼此相反 相同长度的。 为相同长度的整数列表对指定一个任意值 我试着写一些代码: let length xs ys = List.length xs = List.length ys let samelength = Arb.filter length Arb.from<
List.zip : ('a list -> 'b list -> ('a * 'b) list)
及
在对列表进行操作的条件下,它们彼此相反
相同长度的。
为相同长度的整数列表对指定一个任意值
我试着写一些代码:
let length xs ys =
List.length xs = List.length ys
let samelength =
Arb.filter length Arb.from<int list>
当然,我有错误类型不匹配:
错误:键入mistmatch。应具有类型int
,但此处具有类型任意
编辑
我解决了这个练习,但当我进行测试时,我的生成器似乎不工作,似乎调用了另一个生成器
let samelength (xs, ys) =
List.length xs = List.length ys
let arbMyGen2 = Arb.filter samelength Arb.from<int list * int list>
type MyGeneratorZ =
static member arbMyGen2() =
{
new Arbitrary<int list * int list>() with
override x.Generator = arbMyGen2 |> Arb.toGen
override x.Shrinker t = Seq.empty
}
let _ = Arb.register<MyGeneratorZ>()
let pro_zip (xs: int list, ys: int list) =
(xs, ys) = List.unzip(List.zip xs ys)
do Check.Quick pro_zip
让samelelength(xs,ys)=
List.length xs=List.length ys
让arbMyGen2=Arb.filter从中采样Arb.from的长度
类型MyGeneratorZ=
静态成员arbMyGen2()=
{
使用
覆盖x.Generator=arbMyGen2 |>Arb.toGen
覆盖x.收缩器t=序列空
}
让uz=Arb.register()
让pro_zip(xs:int-list,ys:int-list)=
(xs,ys)=List.unzip(List.zip xs-ys)
一定要检查,快拉拉链
我得到一个错误:
错误:System.ArgumentException:list1比list2短1个元素
但是为什么呢?我的生成器应该只生成两个长度相同的列表。如果我们查看,并将鼠标悬停在过滤器的定义上,您将看到Arb.filter的类型是:
pred:('a -> bool) -> a:Arbitrary<'a> -> a:Arbitrary<'a>
但这方面仍然存在问题。具体而言,如果我们查看,我们会发现以下警告:
使用Gen.filter
时,请确保提供一个返回true
几率较高的谓词。如果谓词丢弃“过多”候选项,则可能会导致测试运行变慢,或根本不终止
顺便说一句,这同样适用于Arb.filter
和Gen.filter
。从代码当前的状态来看,这是一个问题,因为您的过滤器将丢弃大多数列表对。由于列表是相互独立生成的,通常情况下它们的长度不同,因此您的过滤器在大多数情况下都会返回false
。我建议采用不同的方法。既然你说过这是一个练习,我就不为你写代码了,因为你会通过自己做来学到更多;我只给你一个你想采取的步骤的概要
生成一个非负intn
,它将是该对中两个列表的大小。(对于奖励积分,请使用Gen.size
获取您应该生成的数据的“当前大小”,并将n
生成为介于0和size
之间的值,以便您的列表对生成器,如FsCheck的默认列表生成器,将创建开始较小但逐渐变大的列表)
使用Gen.listOfLength n
生成两个列表。(您甚至可以通过Gen.two(Gen.listOfLength n)
轻松生成一对大小相同的列表)
不要忘记为一对列表编写一个适当的收缩器,因为练习希望您生成一个适当的任意
,而没有收缩器的任意
在实践中不是很有用。您可能可以在此处使用Arb.mapFilter
执行某些操作,其中映射器是id
,因为您已经在生成匹配长度的列表,但过滤器是您的length
谓词。然后使用Arb.fromGenShrink
将生成器和收缩器函数转换为适当的任意
实例
如果这个大纲还不足以让你工作,那就再问一个问题,看看你在哪里被卡住了,我很乐意尽我所能帮助你
编辑:
在试图使用sizegen
编写列表生成器的编辑中,以下代码无效:
let listgen =
let size = sizegen
let xs = Gen.listOfLength size
let ys = Gen.listOfLength size
xs, ys
这里的sizegen
是一个Gen
,您需要从中提取int
参数。有几种方法可以做到这一点,但最简单的是FsCheck为我们提供的gen{…}
计算表达式
顺便说一句,如果你不知道什么是计算表达式,它们是F#最强大的特性之一:它们非常复杂,但它们允许你编写非常简单的代码。你应该把它们放在书签上,并计划以后阅读。如果你在第一次、第二次、甚至第五次阅读时不理解它们,不要担心:那很好。只要继续回到这两篇系列文章,在实践中使用计算表达式,如gen
或seq
,最终概念就会变得清晰。每次你读这些系列文章,你都会学到更多,当它在你的大脑中“咔嗒”一声响起时,你就会更接近启蒙时刻
但是回到你的代码。正如我所说,您希望使用gen{…}
计算表达式。在gen{…}
表达式中,let代码>分配将把Gen
对象“展开”到生成的Foo
中,然后您可以在进一步的代码中使用该对象。这就是你想用size
int来做的。所以我们将在你的代码周围包装一个gen{…}
表达式,并得到以下结果:
let listgen =
gen {
let! size = sizegen
let xs = Gen.listOfLength size
let ys = Gen.listOfLength size
return (xs, ys)
}
注意,我还在最后一行添加了return
关键字。在计算表达式中,return
与let有相反的效果代码>。let
关键字展开值(类型从Gen
到Foo
),而return
关键字包装值(类型从Foo
到Gen
)。因此,return
行获取一个int list*int list
并将其转换为一个Gen
。有一些非常复杂的代码在幕后进行,但是在计算表达式的表面级别,您只需要
let length (xs,ys) =
List.length xs = List.length ys
let samelength =
Arb.filter length Arb.from<int list * int list>
let listgen =
let size = sizegen
let xs = Gen.listOfLength size
let ys = Gen.listOfLength size
xs, ys
let listgen =
gen {
let! size = sizegen
let xs = Gen.listOfLength size
let ys = Gen.listOfLength size
return (xs, ys)
}