2017-01-02 70 views
2

我有興趣在更大圖像類型的層次結構中定義基元類型(顏色通道)。由於所討論的類型代表了一點,所以將其可能值限制爲僅在0到255範圍內的整數似乎是明智的。但是,我不知道在類型級別實現這種約束是通常在OCaml的類型系統中完成的。將自定義類型定義爲類型級別的整數子集

type channel = int (* restrict to range 0 -> 255 *)

如果這樣做OCaml的類型系統中是合法的,應該如何去一個關於在類型級別的整數集定義約束? 更具體地說,如何將一個類型定義爲整數的一個子集(範圍)?

回答

4

另一種解決方案是定義了私人類型的模塊如下:使用的

module type INTERVAL = sig 
    type t = private int 
    val of_int : int -> t (* fails if value outside bounds *) 
end 

let interval a b = (module struct 
    type t = int 

    let of_int v = 
    if v < a || v > b 
    then failwith (Printf.sprintf "Not in interval [%d, %d]" a b) 
    else v 
end : INTERVAL) 

實施例:

let() = 
    let module Small_int = (val (interval 0 255) : INTERVAL) in 
    let x = Small_int.of_int (read_int()) in 
    print_int ((x :> int) * 2) 

模塊內置這種方式允許您使用有限的一組的整數值的。然而,它們有幾個缺點:

  • 在使用運算符之前,您必須將值轉換回整數(使用:>運算符,如示例所示);
  • 該類型本身不給你任何允許的實際邊界的信息;您必須查看實現或閱讀文檔以瞭解類型的含義;
  • 使用的內存空間是一個整數,在這種情況下不是一個字節;
  • 如果你實例化兩個具有相同邊界的模塊,它們的類型t將不兼容。

對於第一個缺點,沒有什麼限制您添加操作模塊類型:

module type INTERVAL = sig 
    type t = private int 
    val of_int : int -> t 
    val (+) : t -> t -> t 
    val print_int : t -> unit 
end 

let interval a b = (module struct 
    type t = int 

    let of_int v = 
    if v < a || v > b 
    then failwith "Not in interval" 
    else v 

    let (+) x y = of_int (x + y) 

    let print_int x = print_int x 
end : INTERVAL) 


let() = 
    let module Small_int = (val (interval 0 255) : INTERVAL) in 
    let x = Small_int.of_int (read_int()) in 
    let y = Small_int.of_int (read_int()) in 
    Small_int.(print_int (x + y)); 
    print_newline() 

第二個缺點可以與你項目的文檔中聲明的一些約定來克服。

當您想要確保給予函數的輸入位於某個「合法」範圍內時,這有時很有用。如果你是OCaml的新手,我不確定你想使用它,但是仍然可以知道它可以完成。

+1

不錯的解決方案。通過這種方式,你甚至可以執行你想得到的算術:+可以觸發一個異常,或者執行一些模塊化的算術。 –

1

如果您定義了這樣的子類型,Ocaml如何派生適用於這些子類型的操作? (+, - ,*, - )。初始類型和子類型之間的操作?

除Ocaml中的對象外,沒有辦法通過縮小另一種類型的定義來定義約束類型。

在你的情況下,channel應映射到char類型 - 但它仍然需要定義實現算法所需的所有操作。

+0

映射'channel'爲'char'是一個神奇的解決方案。當我們在操作中像維算術一樣簡單地維護這些約束的頭痛時,我們所建議的方式不能限制類型。儘管如此,我不想排除這種可能性。 –

1

也許你可以使用一個函子:

module type Elt_type = 
    sig 
    type t 
    val min  : t 
    val max  : t 
    val (<)  : t -> t -> bool 
    val (>)  : t -> t -> bool 
    val (+)  : t -> t -> t 
    val print  : t -> unit 
    end 

module Make (Elt : Elt_type) = 
    struct 
    type t'  = Set of Elt.t 
    let of_t x = 
     if Elt.(<) x Elt.min || Elt.(>) x Elt.max 
      then failwith "Not in interval" 
     else Set x 
    let to_t x' = let Set x=x' in x 
    let (+) x' y'= of_t (Elt.(+) (to_t x') (to_t y')) 
    let print x' = Elt.print (to_t x') 
    end 

module Int =Make (
    struct 
    type t  = int 
    let min  = 1 
    let max  = 10 
    let (<)  = Pervasives.(<) 
    let (>)  = Pervasives.(>) 
    let (+)  = Pervasives.(+) 
    let print = Pervasives.print_int 
    end) 

測試:

# open Int 
# let x = of_t 2;; 
val x : Int.t' = Set 2 
# let y = of_t 3;; 
val y : Int.t' = Set 3 
# print (x + y);; 
5- : unit =() 
相關問題