SML 中的 int -> int -> int 和 (int*int) -> int 有什么区别?

What is the difference between int -> int -> int and (int*int) -> int in SML?

我注意到在 SML 中有两种定义函数的方法。例如,如果您使用 add 函数,则有两种方法:

fun add x y = x+y;

fun add(x,y) = x+y;

第一种方法创建函数类型为:

val add = fn : int -> int -> int

第二个创建函数类型为:

val add = fn : int * int -> int

对于相同的功能,这两种类型有什么区别?还有为什么同一个功能有两种类型?

如果我们从您的两个定义中删除语法糖,它们将变为:

val add = fn x => fn y => x+y

val add = fn xy =>
    case xy of
        (x,y) => x+y

所以在第一种情况下 add 是一个函数,它接受一个参数 x 和 returns 另一个函数,它接受一个参数 y 然后 returns x+y。这种通过返回另一个函数来模拟多个参数的技术称为柯里化。

第二种情况add是一个函数,它接受一个元组作为参数,然后将元组的两个元素相加。

这也解释了两种不同的类型。 -> 是函数箭头,它关联到右边,意思是 int -> int -> intint -> (int -> int) 相同,描述了一个接受 int 和 returns 的函数 int -> int函数。

另一方面,

* 是用于元组类型的语法,即 int * int 是包含两个整数的元组类型,因此 int * int -> int(括号中为 (int * int) -> int 因为 * 的优先级高于 ->) 描述了一个接受两个整数元组和 returns 一个整数的函数。

这两个函数之所以不同是因为 Currying 现象。具体来说,Currying 是一种能力,可以将具有 dom(f) = R^{n} 的任何函数编写为从 R n 次获取输入的函数。这基本上是通过确保每个输入 return 是下一个变量接受的函数来实现的。这就是 -> 符号所代表的 - 它是 Curry-Howard Isomorphism 的基本结果。所以:

fun addCurry x y = x + y (* int -> int -> int *)
fun addProd (x,y) = x + y (* (int*int) -> int *)

告诉我们 addCurryaddProd 的简化形式,可以用于 "substitute" 和 return 变量。因此,addProdaddCurry 是上下文等效的。但是,它们 不是 语义等价的。 (int*int) 是产品类型。它说它期望 input1=intinput2=intint -> int 说它需要一个 int 和 return 一个 int。是箭型的。

如果您有兴趣,您可能还想知道 SML 函数只有两种参数:

1) 咖喱

2) 元组 - 因此,fun addProd (x,y)(x,y) 表示为函数参数的元组。