2010-07-08 8 views
3

J'ai commencé à utiliser FsUnit pour tester le code F #. Il permet d'exprimer l'affirmation dans le style F #, par exemple:FsUnit et vérification de l'égalité des nombres à virgule flottante

[<Test>] 
member this.``Portugal voted for 23 countries in 2001 Eurovision contest``() = 
    this.totalVotes 
    |> getYearVotesFromCountry "Portugal" 2001 
    |> Seq.length 
    |> should equal 23 

Note « doit être égale à 23 » que je reçois de FsUnit. Voici comment FsUnit définit:

x = laisser égale nouvelle EqualConstraint (x)

Avec nombres à virgule flottante, il est pas aussi simple que cela. Je dois utiliser EqualConstraint avec la méthode Within. Il convient naturellement C#:

Assert.That(result).Is.EqualTo(1).Within(0.05); 

Bien sûr, je voudrais pouvoir écrire en F #:

result |> should equal 1 within 0.05 

Mais cela ne fonctionne pas. J'ai fini par la définition d'une nouvelle fonction:

let almostEqual x = (new EqualConstraint(x)).Within(0.01) 

ou si je veux précision paramétrisation, je peux spécifier comme second argument:

let equalWithin x y = (new EqualConstraint(x)).Within(y) 

Mais aucun d'entre eux sont assez. Je voudrais définir la fonction "within" d'une manière plus naturelle pour F #, donc elle peut être utilisée avec equal. F # ne supporte pas la surcharge de méthode, donc il semble que je ne puisse pas le définir de telle manière que "equal" puisse être utilisé seul ou avec "within".

Des idées?

Répondre

12

Ceci est un problème intéressant! Je ne pense pas que vous pouvez ajouter within 0.05 à la définition existante de should equal en aucune façon. Pour ce faire, vous devez ajouter un paramètre à la fonction should, mais cela nécessite un nombre fixe de paramètres dans la bibliothèque. Une manière d'écrire ceci élégamment dans F # serait de créer l'opérateur +/-. Notez que vous devez toujours utiliser entre parenthèses, mais il semble assez soignée:

0.9 |> should equal (1.0 +/- 0.5) 

L'opérateur construit simplement une valeur d'un type spécial qui doit être explicitement traité dans la fonction equal. Voici la mise en œuvre:

type Range = Within of float * float 
let (+/-) (a:float) b = Within(a, b) 

let equal x = 
    match box x with 
    | :? Range as r -> 
     let (Within(x, within)) = r 
     (new EqualConstraint(x)).Within(within) 
    | _ -> 
    new EqualConstraint(x) 
+0

Wow! C'est vraiment besoin en effet!Merci pour une autre excellente suggestion. Et celui-ci est également basé sur des opérateurs personnalisés. –

0

Note de terminologie: F # prend en charge méthode surcharge; il ne supporte pas la surcharge fonctions let-bound (fonctions 'libres' définies dans les modules).

Vous pourriez, par ex. faites-le should.equal avec un point, de sorte que equal est une méthode sur l'objet should, que vous pourriez surcharger. Bien que cela n'aiderait toujours pas, puisque vous ne pouvez pas surcharger les arguments curry. Hmmm.

Ok, je n'ai pas beaucoup utile à offrir. Personnellement, je n'aime pas ce type de sucres syntaxiques dans les bibliothèques.

+0

Vous avez raison Brian dans la terminologie. Je voulais dire des fonctions let-bound bien sûr. Et j'aime ce sucre syntaxique. Je pense que c'est essentiel en F #. –

Questions connexes