3

编译器接受以下行:

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

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

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

类型不匹配。期望任意 -> 'a 但给定 a ('b -> 'c) -> 属性 'Arbitrary' 类型与类型 ''a -> '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
4

3 回答 3

7

在第二行,您的论点顺序错误。

函数应用具有最高的优先级,所以它首先被应用,在其他一切之前。运算符<|and|>之后应用,它们具有相同的优先级,因此首先应用左侧的运算符,然后应用右侧的运算符。因此,如果您考虑这一行:

x |> y <| z

首先,您应用左管道并获得:

(y x) <| z

应用正确的管道后,您将获得:

y x z

但是,如果您考虑第二行,则相反:

x <| y (z)

应用管道后:

y (z) x
于 2016-08-17T14:33:50.497 回答
3

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

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 您提供的示例中的所有管道运算符似乎都使事情变得模糊而不是帮助。通常不建议将管道用于单行,除非它有助于自动完成。

于 2016-08-17T14:34:39.420 回答
2

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

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

由于Prop.forAllis的第一个参数Arbitrary<'a>,编译器尝试将函数推断为Arbitrary,但事实并非如此。

于 2016-08-17T14:36:11.453 回答