2015-03-01 27 views
6

Czy istnieje sposób generowania ciągu znaków w FsCheck, wybierając tylko jeden element z listy łańcuchów, a następnie łącząc wynik?Generatory FsCheck przez wybranie z puli możliwości

Po prostu całkowicie utknąłem i nie mogę tego rozgryźć. Przyjrzałem się repozytorium docs i github za coś podobnego. I większość czytania przeczytałem na FsCheck od FSharpForFunAndProfit.

To jest coś, co chciałbym być na myśli:

let rand = System.Random() 
let randInt max = rand.Next(0, max) 

let selectLetter (string: string) = 
    let whichLettersIndex = String.length string |> randInt 
    string.Substring(whichLettersIndex, 1) 

let generateOddlySpelledWord listOfStrings = 
    List.map selectLetter listOfStrings 
    |> String.concat "" 

let usingGenerateOddlySpelledWord = 
    generateOddlySpelledWord ["zZ"; "oO0Ò"; "eEê"] 

To powinno generować coś jak „Z0ê” lub „Zoe”.

+0

Napisz funkcję chcesz, generuje 'seq' ciąg następnie zastosować' Gen.elements'. –

Odpowiedz

6

Czy to robi to, co chcesz?

open FsCheck 

let createGenerators (l : string seq) = 
    l |> Seq.map Gen.elements |> Seq.toList 

type OddlySpelledWords = 
    static member String() = 
     ["zZ"; "oO0Ò"; "eEê"] 
     |> createGenerators 
     |> Gen.sequence 
     |> Gen.map (List.map string >> String.concat "") 
     |> Arb.fromGen 

Test Ad-hoc:

open FsCheck.Xunit 

[<Property(Arbitrary = [| typeof<OddlySpelledWords> |])>] 
let test (s : string) = 
    printfn "%s" s 

wyjściowa (obcięty):

z0ê 
    ZÒe 
    ZOe 
    zoê 
    ZÒe 
    zoê 
    Z0e 
    zoê 
    z0ê 
    ZOe 
    zÒê 
    z0E 
    zoe 

Wyjaśnienie

Funkcja createGenerators ma typ seq string -> Gen<char> list, a to tworzy Gen z każdy ciąg znaków przy użyciu Gen.elements, ponieważ ciąg znaków jest również char seq; Gen.elements tworzy Gen, który wybierze jedną z tych wartości char z każdego ciągu.

Następnie używa Gen.sequence, aby przekonwertować Gen<char> list na Gen <char list>, a następnie stamtąd mapować.


BTW, można także wbudować createGenerators:

type OddlySpelledWords = 
    static member String() = 
     ["zZ"; "oO0Ò"; "eEê"] 
     |> List.map Gen.elements 
     |> Gen.sequence 
     |> Gen.map (List.map string >> String.concat "") 
     |> Arb.fromGen 
+0

Dzięki Mark! Wygląda na to, że zadziała. – Sobieck

+0

+1 Świetna odpowiedź, a także dobrze wykonane (jak pokazano na [jego edycje] (http://stackoverflow.com/posts/28798955/revisions))! - A może użyć 'List.reduce (+)' zamiast 'String.concat" "? –

+2

Problem z 'List.reduce' jest taki, że jest delikatny, więc staram się go unikać. Spróbuj tego, jeśli mi nie wierzysz: 'List.empty |> List.reduce (+)'. –