我想使用以下签名使我的代码在字符串和数组(真正的任何可索引类型)上通用:
module type Indexable = sig
type 'a t
val get : int -> 'a t -> 'a
end
Run Code Online (Sandbox Code Playgroud)
module MyCode (I : Indexable) = struct ... end
但是我当然不能将我的签名应用于字符串,如下所示:
module StrMyCode = MyCode(struct
type 'a t = string
let get i a = a.[i]
end)
Run Code Online (Sandbox Code Playgroud)
有什么方法可以解决这个问题吗?或者也许是另一种不同的方式?我知道在最糟糕的情况下我可以使用字符数组,但我宁愿将代码保存在丑陋的演员表中,这是我之前想到的,所以我想得到一个明确的答案.
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
Run Code Online (Sandbox Code Playgroud)
数组当然可以是Indexable平凡的:
module IndexableArray = struct
type 'a t = 'a array
let get i x = x.(i)
end
Run Code Online (Sandbox Code Playgroud)
对于字符串,您可以使用具有单个构造函数的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
Run Code Online (Sandbox Code Playgroud)
这是我用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)
Run Code Online (Sandbox Code Playgroud)
如果我加载到顶层,我得到这个:
val index : 'a indexable -> int -> 'a = <fun>
val main : unit -> unit = <fun>
# main ();;
1
b
- : unit = ()
#
Run Code Online (Sandbox Code Playgroud)
这可能不像你想要的那样一般.