2017-11-02 24 views
1

パターンに一致するランダムな文字列(例えば、abcd)とともにランダムなグロブ構文パターン(例えば、a*c?)を生成するFsCheckジェネレータを書きました。しかし、私の解決策は可変変数を使用しており、私はむしろそれを恥じています。見て:textが可変であることと、その値がループ内に蓄積された方法をFsCheckジェネレータのリストを単一の値に累積する方法は?

open FsCheck 

type TestData = {Pattern: string; Text: string} 

let stringFrom alphabet = 
    alphabet |> Gen.elements |> Gen.listOf |> Gen.map (List.map string >> List.fold (+) "") 

let singleCharStringFrom alphabet = 
    alphabet |> Gen.elements |> Gen.map string 

let matchingTextAndPatternCombo = gen {  
    let toGen = function 
     | '*' -> stringFrom ['a'..'f'] 
     | '?' -> singleCharStringFrom ['a'..'f'] 
     | c -> c |> string |> Gen.constant 

    let! pattern = stringFrom (['a'..'c']@['?'; '*']) 
    let mutable text = "" 

    for gen in Seq.map toGen pattern do 
     let! textPart = gen 
     text <- text + textPart 

    return {Pattern = pattern; Text = text} 
} 

は注意してください。

私の根性はtextに発電機をfoldする方法がなければならないことを教えて、私は(まだ)ボンネットの下にどのようlet!作品を理解していないので、私は、どのように理解することはできません。私は次のようなものを考えていました:

let! text = pattern |> Seq.map toGen |> Seq.fold (?) (Gen.constant "") 

私は正しい道にいますか? foldのアキュムレータとシードはどのように見えるのですか?

答えて

3

foldのようなものをここで使用することができることをあなたの直感は正しいですが、問題は、折りたたみ機能がGen<'T>計算返しfoldのバージョン必要があるだろうということである - のF#からList.foldが動作しませんので、通常のを。この場合、私は突然変異を使っても問題ないと思います。あなたのコードは私にとってははっきりしています。 Genモジュール内の関数を使ってみると

、私はfoldのバージョンが表示されていないが、私はGen.sequenceはあなたがきれいに必要なものを行うことができます考える:

let! textParts = Gen.sequence (Seq.map toGen pattern) 
let text = String.concat "" textParts 

Gen.sequence機能は、発電機のリストを受け取り、これらのジェネレータを使用して値のリストを生成するジェネレータを返します。この方法では、すべてのテキストパーツを一度に生成してから、結果を連結することができます。

あなたがあなた自身のfoldを書いて、それを使用したい場合は、それはこのような何か になります:発電機を折る

let rec fold f init xs = gen { 
    match xs with 
    | [] -> return init 
    | x::xs -> 
     let! state = f init x 
     return! fold f state xs } 

コードは次のようになります。

let! text = 
    Seq.map toGen pattern |> List.ofSeq |> fold (fun (text:string) g -> gen { 
    let! textPart = g 
    return text + textPart }) "" 

私はそうではありませんこれをテストしたので、バグがある可能性があります(おそらく、間違った方法で折り返してしまうため、逆の文字列になります)が、一般的な構造が正しいはずです。一方

+0

私は、次のアキュムレータを思い付いた: '楽しいcurrGenネクストジェン - > currGen >> = - |'(> NextGenの楽しいテキスト> Gen.map((+)テキスト))。しかし、 'Gen.sequence'によるあなたのアプローチは、もっと読みやすく、慣用的です。ありがとう! –

関連する問題