具有成员函数的管道运算符

时间:2016-12-24 22:30:20

标签: f#

我可以使用管道运算符的模块和静态成员函数的函数。我可以将它与非静态成员函数一起使用吗?

我的课程:

type MyClass =
    class
        new() = {}

        member this.isZero(number: int): bool =
            number = 0

        static member returnInt(): int =
            33
    end

使用静态成员:

MyClass.returnInt() |> Console.WriteLine // prints 33

使用非静态成员:

let foo = new MyClass()
foo.isZero(2) |> Console.WriteLine // prints false

我想使用我对象的非静态函数。语法无效:

let foo = new MyClass()
foo |> member MyClass.isZero(2) |> Console.WriteLine

我尝试使用F#的清晰语法。

1 个答案:

答案 0 :(得分:3)

如果您已经拥有该实例的标识符,例如问题中的foo,则foo.isZero(2) |> ...简短易读。在较长的管道内,使用lambda表达式:

funcThatReturnsMyClass(...) |> fun m -> m.isZero(2) |> Console.WriteLine

注意优先顺序;当事情变得复杂时,你可能想在lambda周围添加括号,即|> (fun m -> ...) |>

如果这种情况发生了很多,添加一些curried函数会有所帮助。这适用于实例成员以大写字母开头的约定,而静态成员或let-bound函数以小写字母开头。这样,如果您需要管道很多但又想支持点符号,您可以定义两种语法:

type MyClass2 (magicInt : int) =
    member __.IsMagic i = i = magicInt
    static member inline isMagic i (instance : MyClass2) = instance.IsMagic i

现在,您可以在实例上使用点符号,还可以使用管道:|> MyClass2.isMagic 2 |> ...

isMagic的实施可能看起来过多,但重点是转发到其他实施,而无需额外费用。这通常比复制实现更好,即使实现很短,因为它不会创建可能不同步的额外变体,可能需要额外的测试等等。