满足谓词的 FsCheck 自定义列表生成器

FsCheck custom generator of lists satisfying a predicate

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

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

FsCheck manual 中所述,谓词对随机列表成立的可能性应该很高。 不幸的是,这个假设在我的案例中不成立。因此,我需要为满足谓词的列表定义自定义生成器。

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

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

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

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

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
  }

不过我还没有检查给你什么样的发行版。当然,如果列表永远不会收敛到通过谓词的形式,你就有无限循环(或堆栈溢出)的风险。