如何在数组和字符串上编写仿函数?

时间:2013-01-12 00:58:13

标签: ocaml

我想使用以下签名使我的代码在字符串和数组(真正的任何可索引类型)上通用:

module type Indexable = sig
  type 'a t
  val get : int -> 'a t -> 'a
end

module MyCode (I : Indexable) = struct ... end

但当然我不能将我的签名应用于字符串,如下所示:

module StrMyCode = MyCode(struct
  type 'a t = string
  let get i a = a.[i]
end)

有什么方法可以解决这个问题吗?或者也许是另一种不同的方式?我知道在最坏的情况下我可以使用字符数组,但我宁愿将代码保存在丑陋的演员表中,这是我之前想到的,所以我想得到一个明确的答案。

3 个答案:

答案 0 :(得分:6)

GADT可以与funorized方法一起使用:

module type Indexable = sig
  type 'a t
  val get: int -> 'a t -> 'a
end

module MyCode(I:Indexable) = struct
 let head x = I.get 0 x
end

阵列当然可以Indexable简单地进行:

module IndexableArray = struct
  type 'a t = 'a array
  let get i x = x.(i)
end

对于字符串,您可以使用具有单个构造函数的GADT。但是请注意,为了强制使用多态类型,必须为get添加一些类型注释(否则,推断类型为int -> char t -> char):

module IndexableString = struct
  type 'a t = String: string -> char t
  let of_string s = String s
  let get: type a. int -> a t -> a =
    fun i s -> match s with String s -> s.[i]
end

答案 1 :(得分:5)

这是我使用GADT制作的东西。我只是把头缠在他们周围,所以这里可能有点不对劲。但就我所见,它似乎有效(使用OCaml 4):

type _ indexable =
    | A : 'a array -> 'a indexable
    | C : string -> char indexable

let index (type s) (x: s indexable) i : s =
    match x with
    | A a -> a.(i)
    | C s -> s.[i]

let main () =
    let x = A [| 1; 2 |] in
    let y = C "abc" in
    Printf.printf "%d\n" (index x 0);
    Printf.printf "%c\n" (index y 1)

如果我加载到顶层,我会得到这个:

val index : 'a indexable -> int -> 'a = <fun>
val main : unit -> unit = <fun>
# main ();;
1
b
- : unit = ()
#

这可能不像你要找的那样一般。

答案 2 :(得分:2)

如果将indexable的元素类型声明为单独的类型,则可以执行以下操作:

module type Indexable = sig
  type t
  type elt
  val get : int -> t -> elt
end

module IndexableString : Indexable = struct
  type t = string
  type elt = char
  let get i a = a.[i]
end

module MyCode (I : Indexable) = struct
  (* My code implementation *)
end

module StrMyCode = MyCode(IndexableString)

对于数组,您可以大致相同:

module ArrayIndexable = struct
    type elt = char
    type t = char array
    let get i a = a.(i)
end

现在,如果您希望保持数组的一些灵活性,您可以将上述内容更改为仿函数:

module ArrayIndexable (E : sig type e end) : Indexable with type elt = E.e =
struct
    type elt = e
    type t = elt array

    let get i a = a.(i)
end

它比您正在寻找的多态版本更冗长,但它允许您统一编码“可索引”类型。