(* This is a filter: it tests values of type 'a.
* A filter contains two functions: forbid and f (see the type definition).
*
* We say that a filter:
* - forbids a value x if forbid x returns a non-empty string.
* - accepts a value x if f x returns true
* - rejects a value x if f x returns false
*
* The forbid test is done first: if a value is forbidden, it cannot be accepted or rejected.
*
* Example with an int filter :
* if forbid (-1) returns "a negative number, this is insane!", this means that -1 is a forbidden value.
* if forbid 12 returns "", this means that 12 is not forbidden.
*
* if f 12 returns true, this means that 12 is accepted.
* if f 17 returns false, this means that 17 is rejected (assuming 17 is not forbidden either: forbid 17 returns "")
*)
type 'a filter =
{ forbid: ('a -> string) ;
f: ('a -> bool) }
(* When a filter is applied to a value, it returns one of these. *)
type result = Forbid of string | Accept | Reject
(* Forbid contains the message returned by the forbid function.
* It cannot be empty. *)
(* In some tests, we use some predefined filters :
*
* filter_even : int filter, forbids : negative numbers, accepts : even numbers (2,4,6,8, ...)
* filter_odd : int filter, forbids : 0, accepts : odd numbers (1,3,-5,-7,...)
*
* filter_pair : (int*int) filter, forbids pairs (a,b) when a is a negative number, accepts pairs with equal values, e.g. (4,4)
*
*)