为什么 F# currying "flattens" 函数类型?

Why F# currying "flattens" function type?

以下函数:

let twoInputs x y =
    let sum = x + y
    let product a = sum * a
    product

具有类型:

val twoInputs : x:int -> y:int -> (int -> int)

这是完全合理的,我知道它为什么要来了。但是为什么这个功能:

let oneInput = twoInputs 1

类型为 val oneInput : (int -> int -> int) ?

不应该是int -> (int -> int)吗?

另外,我认为上面的函数应该符合Associative property,所以int -> int -> (int -> int)int -> int -> int -> int应该没有区别。如果是这样,为什么不直接将后者指定为 twoInputs 的函数类型?

括号表示"value of type FsharpFunc<_>",没有括号表示"true CLR method"。在您的示例中,twoInput 被编译为真正的 CLR 方法,但 returns 是 FSharpFunc<_> 类型的值,因此是其类型。但是您的 oneInput 被编译为类型 FSharpFunc<_> 的 class 字段,因此它的类型。

你实际上可以实现相同的效果(即将 true 方法转换为值),即使没有柯里化,非常简单:

> let twoInputs x y =
>     let sum = x + y
>     let product a = sum * a
>     product

> let twoInputsAgain = twoInputs

val twoInputs : x:int -> y:int -> (int -> int)
val twoInputsAgain : (int -> int -> int -> int)

发生这种情况是因为 CLR 不支持 "assigning a method" 的概念,因此 F# 必须通过将 twoInputsAgain 声明为类型 FSharpFunc<_> 的字段然后分配给它来编译它class 的一个实例,它继承自 FSharpFunc<_> 并在 Invoked.

时调用 twoInputs

如果你反编译成C#(我用的是ILSpy),你会看到:

static $Program()
{
    $Program.twoInputsAgain@11 = new Program.twoInputsAgain@11();
}

internal class twoInputsAgain@11 : OptimizedClosures.FSharpFunc<int, int, FSharpFunc<int, int>>
{
    public override FSharpFunc<int, int> Invoke(int x, int y)
    {
        return Program.twoInputs(x, y);
    }
}

总而言之,我想指出这种区别在实践中并不重要,除非你练习一些真正的黑魔法,所以你不应该担心它。