2013-01-12 42 views
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) 

有什麼辦法解決這個問題嗎?或者也許是一種不同的違法行爲?我知道我可以在最糟糕的情況下使用字符數組,但我寧願將代碼從醜陋的表演中保存下來,這是我之前想到的,所以我想爲此得到明確的答案。

回答

5

這是我用GADTs做的東西。我只是圍繞着他們,所以這裏可能會出現一些問題。但它似乎就工作,我可以看到(與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 =() 
# 

這可能不是一般的什麼您正在尋找。

+1

雅這是一個聰明的解決方案,但我走的是仿函數的方法因爲我希望用戶能夠實現他們自己的索引。 – rgrinberg

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 

它比您要查找的多態版本更冗長,但它可讓您對兩個「可索引」類型進行統一編碼。

+0

如何爲數組實現Indexable,然後'type t ='數組'將不會被檢查。即使這個工作,然後我認爲我仍然會失去容器的參數多態性。例如,我不得不分別爲'int array'和'string array'實例化我的函子。也許我所要求的,甚至沒有意義,因爲我想保留我的實例化函數多態的容器中的值除1個案例:字符串。甚至不知道我輸入的內容現在是否有意義... – rgrinberg

+1

是的,我想不出一種方法可以讓參數多態性保持元素類型。 –

6

GADT可以與functorized方法一起使用:

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有一個構造函數。但是請注意,你必須把某些類型的註釋爲獲得以迫使多態型(否則,推斷出的類型爲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 
相關問題