为什么 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<_>
并在 Invoke
d.
时调用 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);
}
}
总而言之,我想指出这种区别在实践中并不重要,除非你练习一些真正的黑魔法,所以你不应该担心它。
以下函数:
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<_>
并在 Invoke
d.
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);
}
}
总而言之,我想指出这种区别在实践中并不重要,除非你练习一些真正的黑魔法,所以你不应该担心它。