我从这里开始
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
它们都起作用。让我感到困惑的是,如何将sip1
和sip1a
设置为采用单个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将多个传入变量视为一个元组?
答案 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 ,完全相反,在语义上互不干扰的非重叠方法。