5.2.3 组合使用元组
当考虑从函数应返回什么样的元组时,关注的主要问题是可组合性(compositionally),即期望如何使用元组?其他哪些函数可能会使用相同类型的元组?与程序中其他的类似情况保持一致吗?
我们用一个示例来演示,将使用两种的方法,表示前面示例中的屏幕坐标和消息,假定已经有一个输出消息的函数printMessage,因此,这里就会省略其定义,函数的声明可能像这样:
> let printMessage (x, y) message =
printfn"[%d, %d] %s" x y message
;;
val printMessage : int * int -> string–> unit
这个类型签名告诉我们,函数有两个参数值:一个是包含坐标的元组,一个是消息。现在,我们要在指定位置输出字符串“Test!”,由前面用过的元组表示,但它包含的消息,我们不感兴趣。清单 5.2 显示了几种方法,取决于我们使用哪种方法表示消息和坐标。
清单 5.2 表示有座标的消息 (F# Interactive)
> let msgAt1 = (50, 100,"Hello!");; | 三个元素的元组
val msgAt1 : int * int * string [1] |
> let (x, y, _) = msgAt1
printMessage (x, y) "Test!";;
[50, 100] Test!
> let msgAt2 = ((50, 100),"Hello!");; | 嵌套了元组的元且
val msgAt2 : (int * int) * string [2] |
> let (coords, _) = msgAt2
printMessage coords "Test!";;
[50, 100] Test!
> printMessage (fst(msgAt2))"Test!";;
[50, 100] Test!
可以发现,第一种方法[1]所创建的元组与 printMessage 函数不兼容,因此,当我们想要组合代码时,首先必须从元组中解析出元素,生成一个新的元组值,才能调用这个函数;使用第二种表示形式,可以做得更好[2],元组的第一个元素本身就是元组,和 printMessage 函数的第一个参数兼容。
这是非常有用的,因为,当我们解析元组以后,就能得到第一个元素,并将它直接用于(函数的)第一个参数值。我们可以做得更好,就像最后一行所演示的,使用 fst 函数来获得元组的第一个元素,然后,直接调用函数。这清楚地说明,为什么元组的逻辑结构很重要;此外,还需要考虑所创建元组的复杂性。