let nth_diff_type i (x, y, z) =
match i with
1 -> x
|2 -> y
|3 -> z
|_ -> raise (Invalid_argument "nth")
所以当前的类型是int->('a,'a,'a)->'a
,对吧?
这意味着x,y,z必须具有相同的类型。
所以我的问题是是否可以赋予它最大的多态,以便x,y,z不需要具有相同的类型?
答案 0 :(得分:8)
不,不是。
OCaml中的函数应该只有一种返回类型。如果返回类型是唯一的,则可以使用不同的参数类型:
let nth_diff_type i (x, y, z) =
match i with
| 1 -> `Fst x
| 2 -> `Snd y
| 3 -> `Thd z
|_ -> raise (Invalid_argument "nth")
// val nth_diff_type :
// int -> 'a * 'b * 'c -> [> `Fst of 'a | `Snd of 'b | `Thd of 'c ] = <fun>
如果您想为三元组创建一些实用程序函数,遗憾的是您必须单独定义它们:
let fst3 (x, _, _) = x
let snd3 (_, y, _) = y
let thd3 (_, _, z) = z
答案 1 :(得分:2)
如果你的函数将任意函数f
应用于元组的任意元素,例如函数f
具有正确的类型,那么你可以在某种程度上使这种多态。
换句话说,如果你考虑一下你可以对你的功能做些什么,你会得出结论,你需要一个正确类型的函数来将它应用于nth_diff_type
的结果,无论那种类型如何。
如果我们假设nth_diff_type
与任何元组一起工作的瞬间,其结果可能是任何类型。您可能会获得int
,string
或更复杂数据类型的实例。我们称之为t
类型。那么你可以用t
类型的值做什么?您只能将其传递给接受t
值的函数。
所以现在的问题是选择正确的函数,并且选择肯定会在非常类似的标准上完成,而不是元组中元素的等级。如果是这样,为什么不简单地传递你的元组,以及可以应用于nth_diff_type
的函数元组,并让它自己执行应用程序?
let nth_diff_type i (a,b,c) (fa,fb,fc) =
match i with
| 1 -> fa a
| 2 -> fb b
| 3 -> fc c
| _ -> failwith "out of range"
-: val nth_diff_type : int -> ( 'a * 'b * 'c) -> (('a -> 'd) * ('b -> 'd) * ('c -> 'd)) -> 'd
答案 2 :(得分:1)
代码在非依赖类型系统中已经是完全多态的。您可以移动到依赖类型系统(但由于复杂性成本,您可能不希望这样),其类型如下:
(n : int) -> (a * b * c) -> (match n with 1 -> a | 2 -> b | 3 -> c | _ -> Error)
除了pad建议之外,您可能还希望使用记录或对象类型进行直接“out projection”操作,而不必先通过模式匹配来定义它。
type ('a, 'b, 'c) triple = { nth1 : 'a; nth2 : 'b; nth3 : 'c }
(* replace *) nth_diff_type 2 v (* by *) v.nth2
使用对象类型(添加不需要事先定义类型的结构风格)
(* replace *) nth_diff_type 2 v (* by *) v#nth2
请注意,这些替换仅适用于常量整数(因为否则您需要整数 - >类型依赖关系)。您可以使用GADT和存在类型来解决某些问题以支持传递特定选择,但是您将不得不为某些事情付出巨大的复杂性成本,而这些成本很可能是由于对现有的简单类型系统不够熟悉而无法理解你真的想做事。