2017-11-02 24 views
1

패턴과 일치하는 임의의 문자열 (예 : abcd)과 함께 임의의 glob 구문 파일 (예 : 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의 어큐뮬레이터 및 시드는 어떤 모양이어야합니까? fold 같은 것이 여기에 사용될 수 있음을

답변

3

당신의 직관은 맞다, 그러나 문제는 폴딩 기능이 Gen<'T> 계산 반환 위치를 fold의 버전이 필요할 것이다 - List.fold 때문에 일반 F 번호에서 작동하지 않습니다를. 이 경우에는 돌연변이를 사용하는 것이 완벽하다고 생각합니다. 코드가 제게는 분명합니다. 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 nextGen -> currGen >> = (재미있는 텍스트 -> nextGen |> Gen.map ((+) text))'. 그러나'Gen.sequence' 접근법은 읽기 쉽고 관용적입니다. 감사! –