2012-03-15 6 views
3

У меня есть набор int, чей ввод я хотел бы ограничить. Я бы хотел, чтобы он вел себя примерно так:Изменение поведения модуля в OCaml

# RestrictedIntSet.add 15 (RestrictedIntSet.make 0 10) 
Exception: 15 out of acceptable range [0 .. 10] 

Как это реализовать? В Java, это может выглядеть примерно так:

Set<Integer> restrictedSet = new HashSet<Integer>() { 
    public boolean add(Integer i) { 
     if (i < lowerBound || i > upperBound) { 
      throw new IllegalArgumentException("out of bounds"); 
     } 
     return super.add(i); 
    } 

Или, чтобы быть менее злоупотребление наследования:

public class RestrictedSet { 

    private int lowerBound; 
    private int upperBound; 
    private Set elems = Sets.newHashSet(); 

    public RestrictedSet(int lowerBound, int upperBound) { 
     this.lowerBound = lowerBound; 
     this.upperBound = upperBound; 
    } 

    public boolean add(Integer i) { 
     if (i < lowerBound || i > upperBound) { 
     throw new IllegalArgumentException("out of bounds"); 
     } 
     return elems.add(i); 
    } 

    /* fill in other forwarded Set calls as needed */ 
} 

Что такое эквивалент, идиоматических способ сделать это в OCaml?

ответ

7

Ну, это зависит, в какой библиотеке вы используете? set?

Используя Set модуль стандартной библиотеки, вы можете сделать следующее:

module type RestrictedOrderedType = sig 
    type t 
    val compare : t -> t -> int 
    val lower_bound : t 
    val upper_bound : t 
end 

module RestrictedSet (Elem : RestrictedOrderedType) = struct 
    include Set.Make(Elem) 

    exception Not_in_range of Elem.t 

    let check e = 
    if Elem.compare e Elem.lower_bound < 0 
    || Elem.compare e Elem.upper_bound > 0 
    then raise (Not_in_range e) 
    else e 

    (* redefine a new 'add' in term of the one in Set.Make(Elem) *) 
    let add e s = add (check e) s 

    let singleton e = singleton (check e) 
end 


(* test *) 
module MySet = RestrictedSet(struct 
    type t = int 
    let compare = compare 
    let lower_bound = 0 
    let upper_bound = 10 
end) 

let test1 = MySet.singleton 3 

let test2 = MySet.add (-3) test1 
(* Exception: Not_in_range (-3) *) 
2

Мне нравится @ ответ gasches'S.

В качестве короткого дополнения: модуль Set OCaml предназначен для создания экземпляром модуля OrderedType, что означает, что вы не можете напрямую использовать собственный файл OCaml int s.

Таким образом, необходимо использовать модуль, который соответствует запрошенной сигнатуре. Определение gasche в описании переменной RestrictedOrderedType делает это и элегантно включает нижние и верхние граничные поля. Более грубый подход заключается в использовании модулей Int32 или Int64 OCaml, которые соответствуют запрошенной сигнатуре OrderedType и жестко кодируют границы в модуле MySet.

Ниже приведена небольшая переформулировка примера Gasche, чтобы проиллюстрировать этот момент.

module MySet = struct 
    include Set.Make(Int32) 

    exception Not_in_range of Int32.t 

    let lower_bound = Int32.of_int 5 

    let upper_bound = Int32.of_int 10 

    let add elt set = 
     if (elt < lower_bound)||(elt > upper_bound) 
     then raise (Not_in_range elt) 
     else add elt set 

    end;; 
Смежные вопросы