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<

我需要一些帮助来做这个关于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<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
。我建议采用不同的方法。既然你说过这是一个练习,我就不为你写代码了,因为你会通过自己做来学到更多;我只给你一个你想采取的步骤的概要

  • 生成一个非负int
    n
    ,它将是该对中两个列表的大小。(对于奖励积分,请使用
    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)
        }