为什么使用向后管道运算符来解决编译错误?

时间:2016-08-17 14:13:15

标签: f# fscheck

编译器接受以下行:

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

但是,当我用括号替换向后的pipline运算符时,我收到一个错误:

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

类型不匹配。期待一个       任意 - &gt; '但是给了一个       ('b - &gt;'c) - &gt;属性“任意”类型与“a - &gt;”类型不匹配“B

我不太清楚这个错误意味着什么。为什么向后流水线操作符编译但括号不编译?

附录

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

3 个答案:

答案 0 :(得分:7)

在第二行,您的参数输入顺序错误。

函数应用程序具有最高优先级,因此它首先应用于其他所有事物之前。之后应用运算符<||>,它们具有相同的优先级,因此首先应用左边的操作符,然后应用右边的操作符。所以,如果你考虑这一行:

x |> y <| z

首先应用左管道并获取:

(y x) <| z

在应用正确的管道之后,你得到:

y x z

但如果你考虑第二行,那就是另一种方式:

x <| y (z)

应用管道后:

y (z) x

答案 1 :(得分:3)

input应该是第一个arg,所以简单

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

管道运算符工作的原因是正向管道更改了解析顺序中的关联。

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

不编译。向后的管道将它改回来。

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)

确实如此。

FWIW您提供的样本中的所有管道操作员似乎比他们的帮助更多地模糊了事物。通常不建议使用管道单线,除非它有助于您自动完成。

答案 2 :(得分:2)

Prop.forAll函数的类型为Arbitrary<'a> -> ('a -> 'b) -> Property。这意味着第一个参数必须是Arbitrary,下一个参数必须是函数('a -> 'b)

当您编写input |> Prop.forAll (fun (a , b) -> add a b = add b a )时,您尝试使用Prop.forAll调用(fun (a , b) -> add a b = add b a ),编译器会将其解释为部分应用的函数。

由于Prop.forAll的第一个参数是Arbitrary<'a>,编译器会尝试将该函数推断为Arbitrary,而不是ArrayList<String> tabs2 = new ArrayList<String> (driver.getWindowHandles()); driver.switchTo().window(tabs2.get(1));