我想使用以下签名使我的代码在字符串和数组(真正的任何可索引类型)上通用:
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)
有什么方法可以解决这个问题吗?或者也许是另一种不同的方式?我知道在最坏的情况下我可以使用字符数组,但我宁愿将代码保存在丑陋的演员表中,这是我之前想到的,所以我想得到一个明确的答案。
答案 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
它比您正在寻找的多态版本更冗长,但它允许您统一编码“可索引”类型。