SML函数参数:元组,currying,类型同义词

时间:2018-12-21 05:18:36

标签: types sml currying

我从这里开始

type int_pair = int * int

然后拥有这些

fun sip1 ((i,j) : int_pair) = (j,i)
fun sip1a (ip : int_pair) = (#2 ip, #1 ip)
fun sip2 (ip : int*int) = (#2 ip, #1 ip)
fun sip3 (i : int, j : int) = (j,i)

具有这些结果

: val sip1 = fn : int_pair -> int * int
: val sip1a = fn : int_pair -> int * int
: val sip2 = fn : int * int -> int * int
: val sip3 = fn : int * int -> int * int

它们都起作用。让我感到困惑的是,如何将sip1sip1a设置为采用单个int_pair变量ip或像元组一样的(i,j)。仅由于类型同义词,它如何处理两者?我只是假设主体中的任何类型的(a,b)都会在返回时默认为int*int类型,而且,在(j,i)的表达式sip1中,似乎不需要引用#1的(sip1a ...)。乍一看有点奇怪。 sip2似乎很简单。但是然后在sip3中,似乎只有两个int进入,而类型为int*int的结果出现了;但是函数类型说它是int * int -> int * int。为什么不像我在其他语言中看到的那样键入int -> int -> int*int? IOW,为什么ML将多个传入变量视为一个元组?

1 个答案:

答案 0 :(得分:0)

在ML中,所有函数仅使用一个参数。但是,当我们需要发送多个参数时,ML会按照唯一的规则:

将传统括号中的参数解释为单个 tuple
fun swap1 (i,j) = (j,i)
: val swap1 = fn : 'a * 'b -> 'b * 'a

上面两个用*隔开的参数表示它们是一个2位元组。

- swap1 (1,2);
val it = (2,1) : int * int

即使变量看起来是分开的,它们仍然被视为单个参数,再次是一个2的元组:

fun swap1a (i : int, j : int) = (j,i)
: val swap1 = fn : int * int -> int * int

如果我们使用type创建类型同义词,例如

type int_pair = int * int
使用int_pair

函数仍被键入为元组:

fun swap2 ((i,j) : int_pair) = (j,i)
: val swap2 = fn : int_pair -> int * int
fun swap2a (ip : int_pair) = (#2 ip, #1 ip)
: val swap2a = fn : int_pair -> int * int
fun swap2b (ip : int*int) = (#2 ip, #1 ip)
: val swap2b = fn : int * int -> int * int

ML还具有 curried 函数,其中多个参数 curried ,基本上意味着这些参数一次只能取一个,而又仅保留一个-参数规则。 Currying使我们可以将函数部分地部分应用,剩下的函数可以在以后进行进一步评估。对于使用currying的函数,特殊的ML语法是简单地使参数包含而不用括号括起来并用空格分隔:

fun swap3 i j = (j,i)
: val swap3 = fn : 'a -> 'b -> 'b * 'a

- swap3 1 2;
val it = (2,1) : int * int

另一种可视化方法是使用匿名函数构造swap3

- val swap3a = fn i => fn j => (j,i)
- swap3a 1 2;
val it = (2,1) : int * int

现在,我们可以设想传入的1 2从右到左解析(讽刺地称为 left-associating la lambda演算:

(fn i => fn j => (j,i))(1,2)
(fn i => (2,i))(1)
(2,1)

请注意,fn i =>...实际上是接受函数作为其输入,在此示例中,匿名函数表达式fn j =>...的值为(2,i)。实际上,可以在REPL中做到这一点:

- ((fn i => fn j => (j,i)) 1) 2;
val it = (2,1) : int * int

正如评论员安德烈亚斯·罗斯伯格(Andreas Rossberg)所说(请参阅上面的评论),在大多数函数式语言中,多个参数函数采用了curring。他指出,从笛卡尔乘积的意义上讲,元组的使用是<笛卡尔笛卡尔()。他还指出,这是 orthogonal ,在这种情况下,这可能意味着这两种处理多个参数(元组和currying)的方法相互之间是 orthogonal ,完全相反,在语义上互不干扰的非重叠方法。