【问题标题】:F# infix overload doesn't workF# 中缀重载不起作用
【发布时间】:2016-06-27 16:55:12
【问题描述】:
let (->>>) lst exp = for i in lst do exp

let result = [0..5] ->>> ([1..5] ->>> printf "hi")
let result2 = for i in [0..5] do for x in [1..5] do printf "hi"

我期待 resultresult2 做同样的事情。但是结果只打印一次。但是,result2 会打印 30 次。这里缺少什么?

【问题讨论】:

    标签: f#


    【解决方案1】:

    在您的运算符定义中,exp 不一定是函数。您定义运算符的方式,exp 是任何值。例如,您可以这样做:

    [0..1] ->>> 42
    

    这将编译甚至运行,因为在您的运算符的定义中没有任何内容需要 exp 参数是一个函数。或者其他任何事情。

    如果你想让exp 在循环体中反复计算,你需要把它变成一个函数,并确保循环体调用它。由于您对它没有任何要求,因此最简单的就是unit -> 'a。您实际上不必声明它的类型,您可以让编译器从它的使用中推断它:

    let (->>>) lst exp = for i in lst do exp()
    

    注意exp 后面的括号——它们表示unit 类型的值,从而使表达式exp() 成为函数应用程序(即函数exp 应用于值())。

    当然,有了这个定义,你就不能写[1..5] ->>> printf "hi",因为printf "hi"不是一个函数。所以你必须写:

    [1..5] ->>> (fun() -> printf "hi")
    

    现在您将打印出五个“hi”。

    这是因为for .. do 语法确实是语言的一个特殊部分,而不是标准库中定义的“只是另一个函数”。巧妙的函数或运算符定义无法真正创建相同的效果。

    如果您想要一种方法来构造比函数和运算符更复杂的语法,请查看computation expressions

    【讨论】:

    • 非常感谢。这个答案很受欢迎。
    • 更现实的解决方案是让 lambda 接收一个元素:... do exp i。这样就可以使用printf "hi %d",甚至不需要笨拙的fun i -> 环绕
    猜你喜欢
    • 2014-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多