2015-03-01 10 views
6

C'è un modo per generare una stringa in FsCheck selezionando solo un elemento da ciascuna di un elenco di stringhe e quindi concatenando il risultato?FsCheck generatori selezionando da pool di possibilità

Sono completamente bloccato e non riesco a capirlo. Ho guardato il docs e nel repository github per qualcosa di simile. E ho fatto la maggior parte della mia lettura su FsCheck dal FSharpForFunAndProfit.

Si tratta di qualcosa di simile a quello che starebbe pensando di:

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ê"] 

Questo dovrebbe generare qualcosa come "Z0ê" o "zoe".

+0

scrivere la funzione che si desidera che genera una stringa di 'seq' quindi applicare' Gen.elements'. –

risposta

6

Fa questo ciò che vuoi?

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 

prova Ad-hoc:

open FsCheck.Xunit 

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

uscita (troncato):

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

Spiegazione

La funzione createGenerators ha il tipo seq string -> Gen<char> list, e crea un Gen da ogni stringa usando Gen.elements, perché una stringa è anche un char seq; Gen.elements crea uno Gen che sceglierà uno di questi valori char da ciascuna stringa.

Quindi utilizza Gen.sequence per convertire il Gen<char> list in un Gen <char list> e quindi le mappe da lì.


BTW, è possibile anche inline 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

Grazie Marco! Sembra che funzionerà. – Sobieck

+0

+1 Ottima risposta, e anche ben realizzata (come mostrato da [le sue modifiche] (http://stackoverflow.com/posts/28798955/revisions))! - Che ne dici di usare 'List.reduce (+)' invece di 'String.concat" "'? –

+2

Il problema con 'List.reduce' è che è fragile, quindi tendo ad evitarlo. Prova questo se non mi credi: 'List.empty |> List.reduce (+)'. –