4

在 OCaml 中

    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 不需要具有相同的类型?

4

3 回答 3

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
于 2013-01-16T17:49:23.690 回答
2

如果您的函数要将任意函数f应用于元组的任意元素,例如该函数f具有正确的类型,那么您可以在某种程度上使这个多态性。

换句话说,如果你考虑一下你可以用你的函数做什么,你会得出结论,你需要一个正确类型的函数来将它应用到 的结果nth_diff_type,无论该类型可能是什么。

如果我们假设某个瞬间nth_diff_type适用于任何元组,那么它的结果可能是任何类型。您可能会得到一个int、一个string或更复杂数据类型的实例。我们称之为类型t。那么你能用 type 的值做什么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
于 2013-01-17T05:34:24.330 回答
1

代码在非依赖类型系统中已经是完全多态的。您可以迁移到依赖类型系统(但您可能不希望,因为复杂性成本),其中类型类似于:

(n : int) -> (a * b * c) -> (match n with 1 -> a | 2 -> b | 3 -> c | _ -> Error)

除了填充建议之外,您可能还希望使用记录或对象类型来进行直接的“外投影”操作,而不必先通过模式匹配来定义它。

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 和存在类型来支持传递特定选择,但是您将不得不为某些事情付出巨大的复杂性成本,这很可能是由于对现有简单类型系统不够熟悉而无法理解如何你真的很想做的事情。

于 2013-01-17T01:17:50.273 回答