【问题标题】:Is it possible to make this fully polymorphic in OCaml?是否可以在 OCaml 中使其完全多态?
【发布时间】:2013-01-16 17:24:47
【问题描述】:

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

【问题讨论】:

  • 在 Haskell 中应该是:Num a => a -> (b,b,b) -> b FWIW,因为文字是多态的。
  • 对不起,我要 OCaml,编辑了我的问题
  • 就目前而言,这是不可能的:在 OCaml 中,一个函数不能同时返回不同类型的值。

标签: functional-programming ocaml


【解决方案1】:

不,不是。

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

【讨论】:

    【解决方案2】:

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

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

    如果我们暂时假设nth_diff_type 可以与任何元组一起使用,那么它的结果可能是任何类型。您可能会得到intstring 或更复杂数据类型的实例。我们称该类型为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
    

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 2020-08-09
        • 1970-01-01
        • 1970-01-01
        • 2018-10-17
        • 1970-01-01
        • 1970-01-01
        • 2013-03-24
        • 1970-01-01
        • 2021-07-02
        相关资源
        最近更新 更多