元组与列表非常不同。对于列表,大小不需要在编译时知道,但对于元组,不仅要在编译时知道元素的数量,而且每个元素的类型都独立于其他元素。
取tl的类型签名:
- tl;
val it = fn : 'a list -> 'a list
它是 'a list -> 'a list - 换句话说,tl 接受 list 的 'a 并返回另一个。为什么我们没有一个用于元组的呢?假设我们想要类似
y = (1,2,3);
tail y; (* returns (2,3) *)
为什么这没有意义?想想tail 的类型签名。那会是什么?
在这种情况下,它显然是
'a * 'b * 'c -> 'b * 'c
获取'a、'b 和'c 的乘积并返回
'b 和 'c。在 ML 中,所有定义的函数都必须具有静态确定的
类型签名。不可能有一个 tail 函数用于元组
处理所有可能的元组大小,因为每个元组大小本质上是一个不同的类型。
'a list
可以是多种列表的类型:[1,2,3,4],或["A", "short", "sentence"],或
【真、假、假、真、假】。在所有这些情况下,类型的值
变量'a 绑定到不同的类型。 (整数、字符串和布尔值)。而'a list 可以是任意大小的列表。
但是采用元组:
(1, true, "yes"); (* (int * bool * string) *)
("two", 2) (* (string, int) *)
("ok", "two", 2) (* (string, string, int) *)
与列表不同,这些都是不同的类型。因此,虽然所有列表的类型签名都很简单 ('a list),但所有元组都没有“通用类型”——2 元组与 3 元组的类型不同。
所以你必须这样做:
y = (7, 8, 9);
(a, b, c) = y;
a 是你的头部,你可以用 (b,c) 重新创建尾部。
或者创建自己的尾巴:
fun tail (a,b,c) = (b, c)
这也让我们直观地理解了为什么这样的函数没有意义:如果不可能定义单个 tail 用于所有元组类型:
fun tail (a,b) = (b)
| tail (a,b,c) = (b, c) (* won't compile *)
您还可以使用# 速记来获取元组的某些元素:
#1 y; (* returns 7 *)
但请注意,#1 不是函数,而是编译时简写。