FsCheck满足条件的列表的自定义生成器

时间:2019-03-22 13:37:40

标签: f# generator fscheck

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

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

FsCheck manual中所述,谓词对于随机列表的保留率应该很高。 不幸的是,这种假设在我看来并不成立。因此,我需要为满足谓词的列表定义自定义生成器。

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

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

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

1 个答案:

答案 0 :(得分:1)

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

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
  }

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