2016-08-17 1 views
3

La ligne suivante est acceptée par le compilateur:Pourquoi l'utilisation d'un opérateur de pipeline en amont résout-elle une erreur de compilation?

input |> Prop.forAll <| fun (a , b) -> add a b = add b a 

Cependant, quand je remplace l'opérateur Pipline en arrière avec des parenthèses, je reçois une erreur:

input |> Prop.forAll (fun (a , b) -> add a b = add b a) 

Type mismatch. Expecting a Arbitrary -> 'a but given a ('b -> 'c) -> Property The type 'Arbitrary' does not match the type ''a -> 'b

Je ne suis pas tout à fait sûr de ce que cette erreur signifie. Pourquoi l'opérateur de pipeline en amont compile-t-il mais pas les parenthèses?

Annexe:

module Arithmetic 

let add a b = 
    a + b 

open FsCheck 
open FsCheck.Xunit 

[<Property(MaxTest=1000, QuietOnSuccess=true)>] 
let ``'a + 'b equals 'b + 'a``() = 

    // Declare generators per type required for function 
    let intGenerator = Arb.generate<int> 

    // Map previously declared generators to a composite generator 
    // to reflect all parameter types for function 
    let compositeGenerator = (intGenerator , intGenerator) ||> Gen.map2(fun a b -> a , b) 

    // Pull values from our composite generator 
    let input = Arb.fromGen compositeGenerator 

    // Apply values as input to function 
    input |> Prop.forAll <| fun (a , b) -> add a b = add b a 
+1

Vous pouvez utiliser 'Arb.generate ' et détruire complètement 'compositeGenerator'. –

+0

Wow, jamais même considéré que ... Merci! –

Répondre

2

La fonction Prop.forAll a le type Arbitrary<'a> -> ('a -> 'b) -> Property. Cela signifie que l'argument premier doit être un Arbitrary et l'argument suivant une fonction ('a -> 'b).

Lorsque vous écrivez input |> Prop.forAll (fun (a , b) -> add a b = add b a), vous tentez d'appeler Prop.forAll avec (fun (a , b) -> add a b = add b a), que le compilateur tente d'interpréter comme une fonction partiellement appliquée.

Puisque le premier argument à Prop.forAll est Arbitrary<'a>, le compilateur tente de déduire la fonction comme Arbitrary, ce qui n'est pas le cas.

+0

Ah ... l'erreur devient si évidente maintenant. smh ... –

7

Sur la deuxième ligne, vous avez vos arguments dans le mauvais ordre.

L'application de fonction a la priorité la plus élevée, elle est donc appliquée en premier, avant tout le reste. Les opérateurs <| et |> sont appliqués après cela, et ils ont la même priorité, de sorte que le premier est appliqué en premier, et le second est appliqué en second. Donc, si vous considérez cette ligne:

x |> y <| z 

D'abord, vous appliquez le tuyau gauche et obtenez:

(y x) <| z 

Et après avoir appliqué la conduite à droite, vous obtenez:

y x z 

Mais si vous considérez la deuxième ligne, c'est l'inverse:

x <| y (z) 

Après avoir appliqué le tuyau:

y (z) x 
3

input devrait être la première arg, si simplement

Prop.forAll input (fun (a , b) -> add a b = add b a) 

La raison pour laquelle l'opérateur de pipeline fonctionne est que le tuyau avant change l'affinité dans l'ordre d'analyse syntaxique.

input |> Prop.forAll (fun (a , b) -> add a b = add b a) 
~ 
input |> (Prop.forAll (fun (a , b) -> add a b = add b a)) 
~ 
Prop.forAll (fun (a , b) -> add a b = add b a) input 

qui ne compile pas. Le tuyau arrière le change en arrière.

input |> Prop.forAll <| fun (a , b) -> add a b = add b a 
~ 
(input |> Prop.forAll) <| (fun (a , b) -> add a b = add b a) 
~ 
(Prop.forAll input) (fun (a , b) -> add a b = add b a) 
~ 
Prop.forAll input (fun (a , b) -> add a b = add b a) 

ce qui est le cas. FWIW Tous les opérateurs de tuyau dans l'échantillon que vous avez donné semblent brouiller les choses plus qu'ils ne les aident. La tuyauterie n'est généralement pas recommandée pour les doublures, sauf dans le cas où cela faciliterait votre autocomplétion.