3

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

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)

有没有办法解决这个问题?或者也许是一种不同的方法?我知道我可以在最坏的情况下使用字符数组,但我宁愿将我的代码从丑陋的演员中拯救出来,这是我之前想到的事情,所以我想得到一个明确的答案。

4

3 回答 3

6

GADT 可以与函数化方法一起使用:

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
于 2013-01-13T11:49:03.470 回答
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 = ()
#

这可能不像您正在寻找的那样普遍。

于 2013-01-12T01:31:19.787 回答
2

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

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

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

于 2013-01-12T01:37:13.070 回答