首页 > 解决方案 > FsCheck 满足谓词的列表的自定义生成器

问题描述

对于给定的谓词pred : 'a list -> bool和生成器gen : Gen<'a>,请考虑以下满足谓词的格式良好列表的生成器:

let wellFormedList pred gen =
   Gen.ofList gen
   |> Gen.filter pred 

FsCheck 手册中所述,谓词应该很有可能适用于随机列表。不幸的是,这个假设不适用于我的情况。因此,我需要为满足谓词的列表定义一个自定义生成器。

如何定义一个从空列表开始并使用新的随机元素扩展它的自定义生成器,直到列表满足谓词?

我可能需要使用gen { }生成器的计算表达式,但我不知道如何。

PS:我知道,与 的原始实现不同wellFormedList,这种自定义生成器的分布在满足谓词的所有列表中并不统一。

标签: f#generatorfscheck

解决方案


好吧,如果我理解正确,我认为应该这样做:

let wellFormedList (predicate:'a list -> bool) (myGen:Gen<'a>) = 
  gen {
    let! initialList = Gen.listOf myGen
    let mutable myList = initialList
    while not <| predicate myList do
      let! newVal = myGen
      myList <- (newVal :: myList)

    return myList      
  }

或者如果你想要一个递归函数:

let wellFormedList (predicate:'a list -> bool) (myGen:Gen<'a>) = 
  gen {
    let rec addIfNecessary listSoFar =
      if predicate listSoFar 
      then gen { return listSoFar }
      else gen { 
        let! newVal = myGen
        return! addIfNecessary (newVal :: listSoFar)
      }

    let! initialList = Gen.listOf myGen
    return! addIfNecessary initialList
  }

我还没有检查给你什么样的分布。当然,如果列表永远不会收敛于通过谓词的形式,那么您将面临无限循环(或堆栈溢出)的风险。


推荐阅读