2017-01-02 57 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 =() 
相关问题