diff --git a/README.md b/README.md index 2f1b6be5..84bb5555 100644 --- a/README.md +++ b/README.md @@ -427,7 +427,7 @@ map = - : unit = () # (* options are good *) - IntMap.get 3 map |> CCOpt.map (fun s->s ^ s);; + IntMap.get 3 map |> CCOption.map (fun s->s ^ s);; - : string option = Some "33" ``` diff --git a/src/core/CCList.ml b/src/core/CCList.ml index 85c2c2fc..a371b964 100644 --- a/src/core/CCList.ml +++ b/src/core/CCList.ml @@ -1073,7 +1073,7 @@ let sublists_of_len ?(last=fun _ -> None) ?offset n l = [[1;2];[3;4]] (subs ~offset:2 2 [1;2;3;4]) [[1;2];[2;3]] (subs ~offset:1 2 [1;2;3]) [[1;2];[4;5]] (subs ~offset:3 2 [1;2;3;4;5;6]) - [[1;2;3];[4]] (subs ~last:CCOpt.return 3 [1;2;3;4]) + [[1;2;3];[4]] (subs ~last:CCOption.return 3 [1;2;3;4]) [[1;2]; [3;4]] (subs 2 [1;2;3;4;5]) *) diff --git a/src/core/CCList.mli b/src/core/CCList.mli index 7c4b5161..489298e7 100644 --- a/src/core/CCList.mli +++ b/src/core/CCList.mli @@ -324,7 +324,7 @@ val sublists_of_len : - [sublists_of_len 2 [1;2;3;4;5;6] = [[1;2]; [3;4]; [5;6]]]. - [sublists_of_len 2 ~offset:3 [1;2;3;4;5;6] = [1;2];[4;5]]. - - [sublists_of_len 3 ~last:CCOpt.return [1;2;3;4] = [1;2;3];[4]]. + - [sublists_of_len 3 ~last:CCOption.return [1;2;3;4] = [1;2;3];[4]]. - [sublists_of_len 2 [1;2;3;4;5] = [[1;2]; [3;4]]]. @param offset the number of elements skipped between two consecutive @@ -333,7 +333,7 @@ val sublists_of_len : @param last if provided and the last group of elements [g] is such that [length g < n], [last g] is called. If [last g = Some g'], [g'] is appended; otherwise [g] is dropped. - If [last = CCOpt.return], it will simply keep the last group. + If [last = CCOption.return], it will simply keep the last group. By default, [last = fun _ -> None], i.e. the last group is dropped if shorter than [n]. @raise Invalid_argument if [offset <= 0] or [n <= 0]. See {!CCList.sublists_of_len} for more details. diff --git a/src/core/CCListLabels.mli b/src/core/CCListLabels.mli index 094eff9a..3ba7215d 100644 --- a/src/core/CCListLabels.mli +++ b/src/core/CCListLabels.mli @@ -327,7 +327,7 @@ val sublists_of_len : - [sublists_of_len 2 [1;2;3;4;5;6] = [[1;2]; [3;4]; [5;6]]]. - [sublists_of_len 2 ~offset:3 [1;2;3;4;5;6] = [1;2];[4;5]]. - - [sublists_of_len 3 ~last:CCOpt.return [1;2;3;4] = [1;2;3];[4]]. + - [sublists_of_len 3 ~last:CCOption.return [1;2;3;4] = [1;2;3];[4]]. - [sublists_of_len 2 [1;2;3;4;5] = [[1;2]; [3;4]]]. @param offset the number of elements skipped between two consecutive @@ -336,7 +336,7 @@ val sublists_of_len : @param last if provided and the last group of elements [g] is such that [length g < n], [last g] is called. If [last g = Some g'], [g'] is appended; otherwise [g] is dropped. - If [last = CCOpt.return], it will simply keep the last group. + If [last = CCOption.return], it will simply keep the last group. By default, [last = fun _ -> None], i.e. the last group is dropped if shorter than [n]. @raise Invalid_argument if [offset <= 0] or [n <= 0]. See {!CCList.sublists_of_len} for more details. diff --git a/src/core/CCMap.ml b/src/core/CCMap.ml index 239ac76e..0ffdc293 100644 --- a/src/core/CCMap.ml +++ b/src/core/CCMap.ml @@ -243,7 +243,7 @@ module Make(O : Map.OrderedType) = struct (M.of_list ["b", 2; "c", 3] \ |> M.update "a" (function _ -> Some 1) \ |> M.update "c" (fun _ -> None) \ - |> M.update "b" (CCOpt.map (fun x -> x * 10)) \ + |> M.update "b" (CCOption.map (fun x -> x * 10)) \ |> M.to_list |> List.sort CCOrd.compare) *) diff --git a/src/core/CCOpt.ml b/src/core/CCOpt.ml index 8e1461c8..8f030690 100644 --- a/src/core/CCOpt.ml +++ b/src/core/CCOpt.ml @@ -1,269 +1 @@ -(* This file is free software, part of containers. See file "license" for more details. *) - -(** {1 Options} *) - -type 'a t = 'a option - -let[@inline] map f = function - | None -> None - | Some x -> Some (f x) - -let map_or ~default f = function - | None -> default - | Some x -> f x - -let map_lazy default_fn f = function - | None -> default_fn () - | Some x -> f x - -let is_some = function - | None -> false - | Some _ -> true - -let is_none = function - | None -> true - | Some _ -> false - -let compare f o1 o2 = match o1, o2 with - | None, None -> 0 - | Some _, None -> 1 - | None, Some _ -> -1 - | Some x, Some y -> f x y - -let equal f o1 o2 = match o1, o2 with - | None, None -> true - | Some _, None - | None, Some _ -> false - | Some x, Some y -> f x y - -let return x = Some x -let some = return -let none = None - -let[@inline] flat_map f o = match o with - | None -> None - | Some x -> f x - -let[@inline] bind o f = flat_map f o - -let (>>=) = bind - -let pure x = Some x - -let (<*>) f x = match f, x with - | None, _ - | _, None -> None - | Some f, Some x -> Some (f x) - -let or_ ~else_ a = match a with - | None -> else_ - | Some _ -> a - -let or_lazy ~else_ a = match a with - | None -> else_ () - | Some _ -> a - -let (<+>) a b = or_ ~else_:b a - -let choice l = List.fold_left (<+>) None l - -let map2 f o1 o2 = match o1, o2 with - | None, _ - | _, None -> None - | Some x, Some y -> Some (f x y) - -let filter p = function - | Some x as o when p x -> o - | _ -> None - -(*$= - None (filter ((=) 0) (Some 1)) - (Some 0) (filter ((=) 0) (Some 0)) - None (filter (fun _ -> true) None) -*) - -let if_ p x = if p x then Some x else None - -let exists p = function - | None -> false - | Some x -> p x - -let for_all p = function - | None -> true - | Some x -> p x - -let iter f o = match o with - | None -> () - | Some x -> f x - -let fold f acc o = match o with - | None -> acc - | Some x -> f acc x - -let get_or ~default x = match x with - | None -> default - | Some y -> y - -let value x ~default = match x with - | None -> default - | Some y -> y - -let get_exn = function - | Some x -> x - | None -> invalid_arg "CCOpt.get_exn" - -let get_exn_or msg = function - | Some x -> x - | None -> invalid_arg msg - -(*$T - (try get_exn_or "ohno" (None:unit option); false with Invalid_argument s->s= "ohno") - 123 = get_exn_or "yes" (Some 123) -*) - -let get_lazy default_fn x = match x with - | None -> default_fn () - | Some y -> y - -let sequence_l l = - let rec aux acc l = match l with - | [] -> Some (List.rev acc) - | Some x :: l' -> aux (x::acc) l' - | None :: _ -> raise Exit - in - try aux [] l with Exit -> None - -(*$T - sequence_l [None; Some 1; Some 2] = None - sequence_l [Some 1; Some 2; Some 3] = Some [1;2;3] - sequence_l [] = Some [] -*) - -let wrap ?(handler=fun _ -> true) f x = - try Some (f x) - with e -> - if handler e then None else raise e - -let wrap2 ?(handler=fun _ -> true) f x y = - try Some (f x y) - with e -> - if handler e then None else raise e - -let to_list o = match o with - | None -> [] - | Some x -> [x] - -let of_list = function - | x::_ -> Some x - | [] -> None - -let to_result err = function - | None -> Error err - | Some x -> Ok x - -let to_result_lazy err_fn = function - | None -> Error (err_fn ()) - | Some x -> Ok x - -let of_result = function - | Error _ -> None - | Ok x -> Some x - -module Infix = struct - let (>|=) x f = map f x - let (>>=) = (>>=) - let (<*>) = (<*>) - let (<$>) = map - let (<+>) = (<+>) - - include CCShimsMkLet_.Make(struct - type 'a t = 'a option - let (>|=) = (>|=) - let (>>=) = (>>=) - let[@inline] monoid_product o1 o2 = match o1, o2 with - | Some x, Some y -> Some (x,y) - | _ -> None - end) -end - -include Infix - -type 'a iter = ('a -> unit) -> unit -type 'a gen = unit -> 'a option -type 'a printer = Format.formatter -> 'a -> unit -type 'a random_gen = Random.State.t -> 'a - -let random g st = - if Random.State.bool st then Some (g st) else None - -exception ExitChoice - -let choice_iter s = - let r = ref None in - begin try - s (function - | None -> () - | (Some _) as o -> r := o; raise ExitChoice - ) - with ExitChoice -> () - end; - !r - -(*$T - choice_iter (Iter.of_list [None; Some 1; Some 2]) = Some 1 - choice_iter Iter.empty = None - choice_iter (Iter.repeat None |> Iter.take 100) = None -*) - -let rec choice_seq s = match s() with - | Seq.Nil -> None - | Seq.Cons (Some x, _) -> Some x - | Seq.Cons (None, tl) -> choice_seq tl - -(*$T - choice_seq (CCSeq.of_list [None; Some 1; Some 2]) = Some 1 - choice_seq CCSeq.empty = None - choice_seq (CCSeq.repeat None |> CCSeq.take 100) = None -*) - -let to_gen o = - match o with - | None -> (fun () -> None) - | Some _ -> - let first = ref true in - fun () -> if !first then (first:=false; o) else None - -let to_iter o k = match o with - | None -> () - | Some x -> k x - -let to_seq = to_iter - -let to_seq o () = match o with - | None -> Seq.Nil - | Some x -> Seq.Cons (x, Seq.empty) - -let pp ppx out = function - | None -> Format.pp_print_string out "None" - | Some x -> Format.fprintf out "@[Some %a@]" ppx x - -let flatten = function - | Some x -> x - | None -> None - -(*$T - flatten None = None - flatten (Some None) = None - flatten (Some (Some 1)) = Some 1 -*) - -let return_if b x = - if b then - Some x - else - None - -(*$T - return_if false 1 = None - return_if true 1 = Some 1 -*) +include CCOption diff --git a/src/core/CCOpt.mli b/src/core/CCOpt.mli index 7b596e39..04133e09 100644 --- a/src/core/CCOpt.mli +++ b/src/core/CCOpt.mli @@ -1,250 +1,3 @@ -(* This file is free software, part of containers. See file "license" for more details. *) +[@@@ocaml.deprecated "use CCOption instead"] -(** {1 Options} *) - -type +'a t = 'a option - -val map : ('a -> 'b) -> 'a t -> 'b t -(** [map f o] applies the function [f] to the element inside [o], if any. *) - -val map_or : default:'b -> ('a -> 'b) -> 'a t -> 'b -(** [map_or ~default f o] is [f x] if [o = Some x], [default] otherwise. - @since 0.16 *) - -val map_lazy : (unit -> 'b) -> ('a -> 'b) -> 'a t -> 'b -(** [map_lazy default_fn f o] if [f o] if [o = Some x], [default_fn ()] otherwise. - @since 1.2 *) - -val is_some : _ t -> bool -(** [is_some (Some x)] returns [true] otherwise it returns [false]. *) - -val is_none : _ t -> bool -(** [is_none None] returns [true] otherwise it returns [false]. - @since 0.11 *) - -val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int -(** [compare comp o1 o2] compares two options [o1] and [o2], - using custom comparators [comp] for the value. - [None] is always assumed to be less than [Some _]. *) - -val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool -(** [equal p o1 o2] tests for equality between option types [o1] and [o2], - using a custom equality predicate [p]. *) - -val return : 'a -> 'a t -(** [return x] is a monadic return, that is [return x = Some x]. *) - -val some : 'a -> 'a t -(** Alias to {!return}. - @since 3.5 *) - -val none : 'a t -(** Alias to {!None}. - @since 3.5 *) - -val (>|=) : 'a t -> ('a -> 'b) -> 'b t -(** [o >|= f] is the infix version of {!map}. *) - -val flat_map : ('a -> 'b t) -> 'a t -> 'b t -(** [flat_map f o] is equivalent to {!map} followed by {!flatten}. - Flip version of {!>>=}. *) - -val bind : 'a t -> ('a -> 'b t) -> 'b t -(** [bind o f] is [f v] if [o] is [Some v], [None] otherwise. - Monadic bind. - @since 3.0 *) - -val (>>=) : 'a t -> ('a -> 'b t) -> 'b t -(** [o >>= f] is the infix version of {!bind}. *) - -val map2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t -(** [map2 f o1 o2] maps ['a option] and ['b option] to a ['c option] using [f]. *) - -val iter : ('a -> unit) -> 'a t -> unit -(** [iter f o] applies [f] to [o]. Iterate on 0 or 1 element. *) - -val fold : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a -(** [fold f init o] is [f init x] if [o] is [Some x], or [init] if [o] is [None]. - Fold on 0 or 1 element. *) - -val filter : ('a -> bool) -> 'a t -> 'a t -(** [filter f o] returns [Some x] if [o] is [Some x] and [f x] is [true], - or [None] if [f x] is [false] or if [o] is [None]. - Filter on 0 or 1 element. - @since 0.5 *) - -val if_ : ('a -> bool) -> 'a -> 'a option -(** [if_ f x] is [Some x] if [f x], [None] otherwise. - @since 0.17 *) - -val exists : ('a -> bool) -> 'a t -> bool -(** [exists f o] returns [true] iff there exists an element for which - the provided function [f] evaluates to [true]. - @since 0.17 *) - -val for_all : ('a -> bool) -> 'a t -> bool -(** [for_all f o] returns [true] iff the provided function [f] evaluates to [true] for all elements. - @since 0.17 *) - -val get_or : default:'a -> 'a t -> 'a -(** [get_or ~default o] extracts the value from [o], or - returns [default] if [o] is [None]. - @since 0.18 *) - -val value : 'a t -> default:'a -> 'a -(** [value o ~default] is similar to the Stdlib's [Option.value] and to {!get_or}. - @since 2.8 *) - -val get_exn : 'a t -> 'a -[@@ocaml.deprecated "use CCOpt.get_exn_or instead"] -(** [get_exn o] returns [x] if [o] is [Some x] or fails if [o] is [None]. - @raise Invalid_argument if the option is [None]. - @deprecated use {!get_exn_or} instead -*) - -val get_exn_or : string -> 'a t -> 'a -(** [get_exn_or msg o] returns [x] if [o] is [Some x] - or fails with [Invalid_argument msg] if [o] is [None]. - @raise Invalid_argument if the option is [None]. - @since 3.4 *) - -val get_lazy : (unit -> 'a) -> 'a t -> 'a -(** [get_lazy default_fn o] unwraps [o], but if [o] is [None] it returns [default_fn ()] instead. - @since 0.6.1 *) - -val sequence_l : 'a t list -> 'a list t -(** [sequence_l [x1; x2; …; xn]] returns [Some [y1; y2; …; yn]] if - every [xi] is [Some yi]. Otherwise, if the list contains at least - one [None], the result is [None]. *) - -val wrap : ?handler:(exn -> bool) -> ('a -> 'b) -> 'a -> 'b option -(** [wrap ?handler f x] calls [f x] and returns [Some y] if [f x = y]. If [f x] raises - any exception, the result is [None]. This can be useful to wrap functions - such as [Map.S.find]. - @param handler the exception handler, which returns [true] if the - exception is to be caught. *) - -val wrap2 : ?handler:(exn -> bool) -> ('a -> 'b -> 'c) -> 'a -> 'b -> 'c option -(** [wrap2 ?handler f x y] is similar to {!wrap} but for binary functions. *) - -(** {2 Applicative} *) - -val pure : 'a -> 'a t -(** [pure x] is an alias to {!return}. *) - -val (<*>) : ('a -> 'b) t -> 'a t -> 'b t -(** [f <*> (Some x)] returns [Some (f x)] and [f <*> None] returns [None]. *) - -val (<$>) : ('a -> 'b) -> 'a t -> 'b t -(** [f <$> o] is like [map f o]. *) - -(** {2 Alternatives} *) - -val or_ : else_:('a t) -> 'a t -> 'a t -(** [or_ ~else_ o] is [o] if [o] is [Some _], [else_] if [o] is [None]. - @since 1.2 *) - -val or_lazy : else_:(unit -> 'a t) -> 'a t -> 'a t -(** [or_lazy ~else_ o] is [o] if [o] is [Some _], [else_ ()] if [o] is [None]. - @since 1.2 *) - -val (<+>) : 'a t -> 'a t -> 'a t -(** [o1 <+> o2] is [o1] if [o1] is [Some _], [o2] if [o1] is [None]. *) - -val choice : 'a t list -> 'a t -(** [choice lo] returns the first non-[None] element of the list [lo], or [None]. *) - -val flatten : 'a t t -> 'a t -(** [flatten oo] transforms [Some x] into [x]. - @since 2.2 *) - -val return_if : bool -> 'a -> 'a t -(** [return_if b x] applies [Some] or [None] depending on the boolean [b]. - More precisely, [return_if false x] is [None], - and [return_if true x] is [Some x]. - @since 2.2 *) - -(** {2 Infix Operators} - @since 0.16 *) - -module Infix : sig - val (>|=) : 'a t -> ('a -> 'b) -> 'b t - (** [o >|= f] is [map f o]. *) - - val (>>=) : 'a t -> ('a -> 'b t) -> 'b t - (** [o >>= f] is the monadic bind. *) - - val (<*>) : ('a -> 'b) t -> 'a t -> 'b t - (** [f <*> o] returns [Some (f x)] if [o] is [Some x] and [None] if [o] is [None]. *) - - val (<$>) : ('a -> 'b) -> 'a t -> 'b t - (** [f <$> o] is like [map f o]. *) - - val (<+>) : 'a t -> 'a t -> 'a t - (** [o1 <+> o2] is [o1] if [o1] is [Some _], [o2] if [o1] is [None]. *) - - (** Let operators on OCaml >= 4.08.0, nothing otherwise - @since 2.8 *) - include CCShimsMkLet_.S with type 'a t_let := 'a option - -end - - -(** Let operators on OCaml >= 4.08.0, nothing otherwise - @since 2.8 *) -include CCShimsMkLet_.S with type 'a t_let := 'a option - -(** {2 Conversion and IO} *) - -val to_list : 'a t -> 'a list -(** [to_list o] returns [[x]] if [o] is [Some x] or the empty list [[]] if [o] is [None]. *) - -val of_list : 'a list -> 'a t -(** [of_list l] returns [Some x] (x being the head of the list l), or [None] if [l] is the empty list. *) - -val to_result : 'e -> 'a t -> ('a, 'e) result -(** [to_result e o] returns [Ok x] if [o] is [Some x], or [Error e] if [o] is [None]. - @since 1.2 *) - -val to_result_lazy : (unit -> 'e) -> 'a t -> ('a, 'e) result -(** [to_result_lazy f o] returns [Ok x] if [o] is [Some x] or [Error f] if [o] is [None]. - @since 1.2 *) - -val of_result : ('a, _) result -> 'a t -(** [of_result result] returns an option from a [result]. - @since 1.2 *) - -type 'a iter = ('a -> unit) -> unit -type 'a gen = unit -> 'a option -type 'a printer = Format.formatter -> 'a -> unit -type 'a random_gen = Random.State.t -> 'a - -val random : 'a random_gen -> 'a t random_gen - -val choice_iter : 'a t iter -> 'a t -(** [choice_iter iter] is similar to {!choice}, but works on [iter]. - It returns the first [Some x] occurring in [iter], or [None] otherwise. - @since 3.0 *) - -val choice_seq : 'a t Seq.t -> 'a t -(** [choice_seq seq] works on [Seq.t]. - It returns the first [Some x] occurring in [seq], or [None] otherwise. - @since 3.0 *) - -val to_gen : 'a t -> 'a gen -(** [to_gen o] is [o] as a [gen]. [Some x] is the singleton [gen] containing [x] - and [None] is the empty [gen]. *) - -val to_seq : 'a t -> 'a Seq.t -(** [to_seq o] is [o] as a sequence [Seq.t]. [Some x] is the singleton sequence containing [x] - and [None] is the empty sequence. - Same as {!Stdlib.Option.to_seq} - Renamed from [to_std_seq] since 3.0. - @since 3.0 *) - -val to_iter : 'a t -> 'a iter -(** [to_iter o] returns an internal iterator, like in the library [Iter]. - @since 2.8 *) - -val pp : 'a printer -> 'a t printer -(** [pp ppf o] pretty-prints option [o] using [ppf]. *) +include module type of CCOption diff --git a/src/core/CCOption.ml b/src/core/CCOption.ml new file mode 100644 index 00000000..50e572e1 --- /dev/null +++ b/src/core/CCOption.ml @@ -0,0 +1,269 @@ +(* This file is free software, part of containers. See file "license" for more details. *) + +(** {1 Options} *) + +type 'a t = 'a option + +let[@inline] map f = function + | None -> None + | Some x -> Some (f x) + +let map_or ~default f = function + | None -> default + | Some x -> f x + +let map_lazy default_fn f = function + | None -> default_fn () + | Some x -> f x + +let is_some = function + | None -> false + | Some _ -> true + +let is_none = function + | None -> true + | Some _ -> false + +let compare f o1 o2 = match o1, o2 with + | None, None -> 0 + | Some _, None -> 1 + | None, Some _ -> -1 + | Some x, Some y -> f x y + +let equal f o1 o2 = match o1, o2 with + | None, None -> true + | Some _, None + | None, Some _ -> false + | Some x, Some y -> f x y + +let return x = Some x +let some = return +let none = None + +let[@inline] flat_map f o = match o with + | None -> None + | Some x -> f x + +let[@inline] bind o f = flat_map f o + +let (>>=) = bind + +let pure x = Some x + +let (<*>) f x = match f, x with + | None, _ + | _, None -> None + | Some f, Some x -> Some (f x) + +let or_ ~else_ a = match a with + | None -> else_ + | Some _ -> a + +let or_lazy ~else_ a = match a with + | None -> else_ () + | Some _ -> a + +let (<+>) a b = or_ ~else_:b a + +let choice l = List.fold_left (<+>) None l + +let map2 f o1 o2 = match o1, o2 with + | None, _ + | _, None -> None + | Some x, Some y -> Some (f x y) + +let filter p = function + | Some x as o when p x -> o + | _ -> None + +(*$= + None (filter ((=) 0) (Some 1)) + (Some 0) (filter ((=) 0) (Some 0)) + None (filter (fun _ -> true) None) +*) + +let if_ p x = if p x then Some x else None + +let exists p = function + | None -> false + | Some x -> p x + +let for_all p = function + | None -> true + | Some x -> p x + +let iter f o = match o with + | None -> () + | Some x -> f x + +let fold f acc o = match o with + | None -> acc + | Some x -> f acc x + +let get_or ~default x = match x with + | None -> default + | Some y -> y + +let value x ~default = match x with + | None -> default + | Some y -> y + +let get_exn = function + | Some x -> x + | None -> invalid_arg "CCOption.get_exn" + +let get_exn_or msg = function + | Some x -> x + | None -> invalid_arg msg + +(*$T + (try get_exn_or "ohno" (None:unit option); false with Invalid_argument s->s= "ohno") + 123 = get_exn_or "yes" (Some 123) +*) + +let get_lazy default_fn x = match x with + | None -> default_fn () + | Some y -> y + +let sequence_l l = + let rec aux acc l = match l with + | [] -> Some (List.rev acc) + | Some x :: l' -> aux (x::acc) l' + | None :: _ -> raise Exit + in + try aux [] l with Exit -> None + +(*$T + sequence_l [None; Some 1; Some 2] = None + sequence_l [Some 1; Some 2; Some 3] = Some [1;2;3] + sequence_l [] = Some [] +*) + +let wrap ?(handler=fun _ -> true) f x = + try Some (f x) + with e -> + if handler e then None else raise e + +let wrap2 ?(handler=fun _ -> true) f x y = + try Some (f x y) + with e -> + if handler e then None else raise e + +let to_list o = match o with + | None -> [] + | Some x -> [x] + +let of_list = function + | x::_ -> Some x + | [] -> None + +let to_result err = function + | None -> Error err + | Some x -> Ok x + +let to_result_lazy err_fn = function + | None -> Error (err_fn ()) + | Some x -> Ok x + +let of_result = function + | Error _ -> None + | Ok x -> Some x + +module Infix = struct + let (>|=) x f = map f x + let (>>=) = (>>=) + let (<*>) = (<*>) + let (<$>) = map + let (<+>) = (<+>) + + include CCShimsMkLet_.Make(struct + type 'a t = 'a option + let (>|=) = (>|=) + let (>>=) = (>>=) + let[@inline] monoid_product o1 o2 = match o1, o2 with + | Some x, Some y -> Some (x,y) + | _ -> None + end) +end + +include Infix + +type 'a iter = ('a -> unit) -> unit +type 'a gen = unit -> 'a option +type 'a printer = Format.formatter -> 'a -> unit +type 'a random_gen = Random.State.t -> 'a + +let random g st = + if Random.State.bool st then Some (g st) else None + +exception ExitChoice + +let choice_iter s = + let r = ref None in + begin try + s (function + | None -> () + | (Some _) as o -> r := o; raise ExitChoice + ) + with ExitChoice -> () + end; + !r + +(*$T + choice_iter (Iter.of_list [None; Some 1; Some 2]) = Some 1 + choice_iter Iter.empty = None + choice_iter (Iter.repeat None |> Iter.take 100) = None +*) + +let rec choice_seq s = match s() with + | Seq.Nil -> None + | Seq.Cons (Some x, _) -> Some x + | Seq.Cons (None, tl) -> choice_seq tl + +(*$T + choice_seq (CCSeq.of_list [None; Some 1; Some 2]) = Some 1 + choice_seq CCSeq.empty = None + choice_seq (CCSeq.repeat None |> CCSeq.take 100) = None +*) + +let to_gen o = + match o with + | None -> (fun () -> None) + | Some _ -> + let first = ref true in + fun () -> if !first then (first:=false; o) else None + +let to_iter o k = match o with + | None -> () + | Some x -> k x + +let to_seq = to_iter + +let to_seq o () = match o with + | None -> Seq.Nil + | Some x -> Seq.Cons (x, Seq.empty) + +let pp ppx out = function + | None -> Format.pp_print_string out "None" + | Some x -> Format.fprintf out "@[Some %a@]" ppx x + +let flatten = function + | Some x -> x + | None -> None + +(*$T + flatten None = None + flatten (Some None) = None + flatten (Some (Some 1)) = Some 1 +*) + +let return_if b x = + if b then + Some x + else + None + +(*$T + return_if false 1 = None + return_if true 1 = Some 1 +*) diff --git a/src/core/CCOption.mli b/src/core/CCOption.mli new file mode 100644 index 00000000..8bbffda9 --- /dev/null +++ b/src/core/CCOption.mli @@ -0,0 +1,250 @@ +(* This file is free software, part of containers. See file "license" for more details. *) + +(** {1 Options} *) + +type +'a t = 'a option + +val map : ('a -> 'b) -> 'a t -> 'b t +(** [map f o] applies the function [f] to the element inside [o], if any. *) + +val map_or : default:'b -> ('a -> 'b) -> 'a t -> 'b +(** [map_or ~default f o] is [f x] if [o = Some x], [default] otherwise. + @since 0.16 *) + +val map_lazy : (unit -> 'b) -> ('a -> 'b) -> 'a t -> 'b +(** [map_lazy default_fn f o] if [f o] if [o = Some x], [default_fn ()] otherwise. + @since 1.2 *) + +val is_some : _ t -> bool +(** [is_some (Some x)] returns [true] otherwise it returns [false]. *) + +val is_none : _ t -> bool +(** [is_none None] returns [true] otherwise it returns [false]. + @since 0.11 *) + +val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int +(** [compare comp o1 o2] compares two options [o1] and [o2], + using custom comparators [comp] for the value. + [None] is always assumed to be less than [Some _]. *) + +val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool +(** [equal p o1 o2] tests for equality between option types [o1] and [o2], + using a custom equality predicate [p]. *) + +val return : 'a -> 'a t +(** [return x] is a monadic return, that is [return x = Some x]. *) + +val some : 'a -> 'a t +(** Alias to {!return}. + @since 3.5 *) + +val none : 'a t +(** Alias to {!None}. + @since 3.5 *) + +val (>|=) : 'a t -> ('a -> 'b) -> 'b t +(** [o >|= f] is the infix version of {!map}. *) + +val flat_map : ('a -> 'b t) -> 'a t -> 'b t +(** [flat_map f o] is equivalent to {!map} followed by {!flatten}. + Flip version of {!>>=}. *) + +val bind : 'a t -> ('a -> 'b t) -> 'b t +(** [bind o f] is [f v] if [o] is [Some v], [None] otherwise. + Monadic bind. + @since 3.0 *) + +val (>>=) : 'a t -> ('a -> 'b t) -> 'b t +(** [o >>= f] is the infix version of {!bind}. *) + +val map2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t +(** [map2 f o1 o2] maps ['a option] and ['b option] to a ['c option] using [f]. *) + +val iter : ('a -> unit) -> 'a t -> unit +(** [iter f o] applies [f] to [o]. Iterate on 0 or 1 element. *) + +val fold : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a +(** [fold f init o] is [f init x] if [o] is [Some x], or [init] if [o] is [None]. + Fold on 0 or 1 element. *) + +val filter : ('a -> bool) -> 'a t -> 'a t +(** [filter f o] returns [Some x] if [o] is [Some x] and [f x] is [true], + or [None] if [f x] is [false] or if [o] is [None]. + Filter on 0 or 1 element. + @since 0.5 *) + +val if_ : ('a -> bool) -> 'a -> 'a option +(** [if_ f x] is [Some x] if [f x], [None] otherwise. + @since 0.17 *) + +val exists : ('a -> bool) -> 'a t -> bool +(** [exists f o] returns [true] iff there exists an element for which + the provided function [f] evaluates to [true]. + @since 0.17 *) + +val for_all : ('a -> bool) -> 'a t -> bool +(** [for_all f o] returns [true] iff the provided function [f] evaluates to [true] for all elements. + @since 0.17 *) + +val get_or : default:'a -> 'a t -> 'a +(** [get_or ~default o] extracts the value from [o], or + returns [default] if [o] is [None]. + @since 0.18 *) + +val value : 'a t -> default:'a -> 'a +(** [value o ~default] is similar to the Stdlib's [Option.value] and to {!get_or}. + @since 2.8 *) + +val get_exn : 'a t -> 'a +[@@ocaml.deprecated "use CCOption.get_exn_or instead"] +(** [get_exn o] returns [x] if [o] is [Some x] or fails if [o] is [None]. + @raise Invalid_argument if the option is [None]. + @deprecated use {!get_exn_or} instead +*) + +val get_exn_or : string -> 'a t -> 'a +(** [get_exn_or msg o] returns [x] if [o] is [Some x] + or fails with [Invalid_argument msg] if [o] is [None]. + @raise Invalid_argument if the option is [None]. + @since 3.4 *) + +val get_lazy : (unit -> 'a) -> 'a t -> 'a +(** [get_lazy default_fn o] unwraps [o], but if [o] is [None] it returns [default_fn ()] instead. + @since 0.6.1 *) + +val sequence_l : 'a t list -> 'a list t +(** [sequence_l [x1; x2; …; xn]] returns [Some [y1; y2; …; yn]] if + every [xi] is [Some yi]. Otherwise, if the list contains at least + one [None], the result is [None]. *) + +val wrap : ?handler:(exn -> bool) -> ('a -> 'b) -> 'a -> 'b option +(** [wrap ?handler f x] calls [f x] and returns [Some y] if [f x = y]. If [f x] raises + any exception, the result is [None]. This can be useful to wrap functions + such as [Map.S.find]. + @param handler the exception handler, which returns [true] if the + exception is to be caught. *) + +val wrap2 : ?handler:(exn -> bool) -> ('a -> 'b -> 'c) -> 'a -> 'b -> 'c option +(** [wrap2 ?handler f x y] is similar to {!wrap} but for binary functions. *) + +(** {2 Applicative} *) + +val pure : 'a -> 'a t +(** [pure x] is an alias to {!return}. *) + +val (<*>) : ('a -> 'b) t -> 'a t -> 'b t +(** [f <*> (Some x)] returns [Some (f x)] and [f <*> None] returns [None]. *) + +val (<$>) : ('a -> 'b) -> 'a t -> 'b t +(** [f <$> o] is like [map f o]. *) + +(** {2 Alternatives} *) + +val or_ : else_:('a t) -> 'a t -> 'a t +(** [or_ ~else_ o] is [o] if [o] is [Some _], [else_] if [o] is [None]. + @since 1.2 *) + +val or_lazy : else_:(unit -> 'a t) -> 'a t -> 'a t +(** [or_lazy ~else_ o] is [o] if [o] is [Some _], [else_ ()] if [o] is [None]. + @since 1.2 *) + +val (<+>) : 'a t -> 'a t -> 'a t +(** [o1 <+> o2] is [o1] if [o1] is [Some _], [o2] if [o1] is [None]. *) + +val choice : 'a t list -> 'a t +(** [choice lo] returns the first non-[None] element of the list [lo], or [None]. *) + +val flatten : 'a t t -> 'a t +(** [flatten oo] transforms [Some x] into [x]. + @since 2.2 *) + +val return_if : bool -> 'a -> 'a t +(** [return_if b x] applies [Some] or [None] depending on the boolean [b]. + More precisely, [return_if false x] is [None], + and [return_if true x] is [Some x]. + @since 2.2 *) + +(** {2 Infix Operators} + @since 0.16 *) + +module Infix : sig + val (>|=) : 'a t -> ('a -> 'b) -> 'b t + (** [o >|= f] is [map f o]. *) + + val (>>=) : 'a t -> ('a -> 'b t) -> 'b t + (** [o >>= f] is the monadic bind. *) + + val (<*>) : ('a -> 'b) t -> 'a t -> 'b t + (** [f <*> o] returns [Some (f x)] if [o] is [Some x] and [None] if [o] is [None]. *) + + val (<$>) : ('a -> 'b) -> 'a t -> 'b t + (** [f <$> o] is like [map f o]. *) + + val (<+>) : 'a t -> 'a t -> 'a t + (** [o1 <+> o2] is [o1] if [o1] is [Some _], [o2] if [o1] is [None]. *) + + (** Let operators on OCaml >= 4.08.0, nothing otherwise + @since 2.8 *) + include CCShimsMkLet_.S with type 'a t_let := 'a option + +end + + +(** Let operators on OCaml >= 4.08.0, nothing otherwise + @since 2.8 *) +include CCShimsMkLet_.S with type 'a t_let := 'a option + +(** {2 Conversion and IO} *) + +val to_list : 'a t -> 'a list +(** [to_list o] returns [[x]] if [o] is [Some x] or the empty list [[]] if [o] is [None]. *) + +val of_list : 'a list -> 'a t +(** [of_list l] returns [Some x] (x being the head of the list l), or [None] if [l] is the empty list. *) + +val to_result : 'e -> 'a t -> ('a, 'e) result +(** [to_result e o] returns [Ok x] if [o] is [Some x], or [Error e] if [o] is [None]. + @since 1.2 *) + +val to_result_lazy : (unit -> 'e) -> 'a t -> ('a, 'e) result +(** [to_result_lazy f o] returns [Ok x] if [o] is [Some x] or [Error f] if [o] is [None]. + @since 1.2 *) + +val of_result : ('a, _) result -> 'a t +(** [of_result result] returns an option from a [result]. + @since 1.2 *) + +type 'a iter = ('a -> unit) -> unit +type 'a gen = unit -> 'a option +type 'a printer = Format.formatter -> 'a -> unit +type 'a random_gen = Random.State.t -> 'a + +val random : 'a random_gen -> 'a t random_gen + +val choice_iter : 'a t iter -> 'a t +(** [choice_iter iter] is similar to {!choice}, but works on [iter]. + It returns the first [Some x] occurring in [iter], or [None] otherwise. + @since 3.0 *) + +val choice_seq : 'a t Seq.t -> 'a t +(** [choice_seq seq] works on [Seq.t]. + It returns the first [Some x] occurring in [seq], or [None] otherwise. + @since 3.0 *) + +val to_gen : 'a t -> 'a gen +(** [to_gen o] is [o] as a [gen]. [Some x] is the singleton [gen] containing [x] + and [None] is the empty [gen]. *) + +val to_seq : 'a t -> 'a Seq.t +(** [to_seq o] is [o] as a sequence [Seq.t]. [Some x] is the singleton sequence containing [x] + and [None] is the empty sequence. + Same as {!Stdlib.Option.to_seq} + Renamed from [to_std_seq] since 3.0. + @since 3.0 *) + +val to_iter : 'a t -> 'a iter +(** [to_iter o] returns an internal iterator, like in the library [Iter]. + @since 2.8 *) + +val pp : 'a printer -> 'a t printer +(** [pp ppf o] pretty-prints option [o] using [ppf]. *) diff --git a/src/core/CCResult.mli b/src/core/CCResult.mli index 6cb9c151..f9033443 100644 --- a/src/core/CCResult.mli +++ b/src/core/CCResult.mli @@ -93,7 +93,7 @@ val get_or : ('a, _) t -> default:'a -> 'a val get_lazy : ('e -> 'a) -> ('a, 'e) t -> 'a (** [get_lazy f e] returns [x] if [e = Ok x], [f msg] if [e = Error msg]. - This is similar to {!CCOpt.get_lazy}. + This is similar to {!CCOption.get_lazy}. @since 3.0 *) val get_or_failwith : ('a, string) t -> 'a diff --git a/src/core/CCVector.ml b/src/core/CCVector.ml index 720f3cd3..4f90df11 100644 --- a/src/core/CCVector.ml +++ b/src/core/CCVector.ml @@ -345,7 +345,7 @@ let rec append_gen a b = match b() with (*$inject let gen x = let small = length in - let print = CCOpt.map (fun p x -> Q.Print.list p (CCVector.to_list x)) x.Q.print in + let print = CCOption.map (fun p x -> Q.Print.list p (CCVector.to_list x)) x.Q.print in Q.make ?print ~small Q.Gen.(list x.Q.gen >|= of_list) *) diff --git a/src/core/containers.ml b/src/core/containers.ml index 6af16a33..e7d181de 100644 --- a/src/core/containers.ml +++ b/src/core/containers.ml @@ -32,7 +32,7 @@ module IO = CCIO module List = CCList module Map = CCMap module Nativeint = CCNativeint -module Option = CCOpt +module Option = CCOption module Ord = CCOrd module Pair = CCPair module Parse = CCParse diff --git a/src/core/containersLabels.ml b/src/core/containersLabels.ml index 191ca597..83342152 100644 --- a/src/core/containersLabels.ml +++ b/src/core/containersLabels.ml @@ -32,7 +32,7 @@ module IO = CCIO module List = CCListLabels module Map = CCMap module Nativeint = CCNativeint -module Option = CCOpt +module Option = CCOption module Ord = CCOrd module Pair = CCPair module Parse = CCParse diff --git a/src/data/CCGraph.ml b/src/data/CCGraph.ml index 5350df0f..0217f151 100644 --- a/src/data/CCGraph.ml +++ b/src/data/CCGraph.ml @@ -347,15 +347,15 @@ let topo_sort ~eq ?rev ~tbl ~graph iter = let tbl = mk_table ~eq:CCInt.equal 128 in \ let l = topo_sort ~eq:CCInt.equal ~tbl ~graph:divisors_graph (Iter.return 42) in \ List.for_all (fun (i,j) -> \ - let idx_i = CCList.find_idx ((=)i) l |> CCOpt.get_exn |> fst in \ - let idx_j = CCList.find_idx ((=)j) l |> CCOpt.get_exn |> fst in \ + let idx_i = CCList.find_idx ((=)i) l |> CCOption.get_exn |> fst in \ + let idx_j = CCList.find_idx ((=)j) l |> CCOption.get_exn |> fst in \ idx_i < idx_j) \ [ 42, 21; 14, 2; 3, 1; 21, 7; 42, 3] let tbl = mk_table ~eq:CCInt.equal 128 in \ let l = topo_sort ~eq:CCInt.equal ~rev:true ~tbl ~graph:divisors_graph (Iter.return 42) in \ List.for_all (fun (i,j) -> \ - let idx_i = CCList.find_idx ((=)i) l |> CCOpt.get_exn |> fst in \ - let idx_j = CCList.find_idx ((=)j) l |> CCOpt.get_exn |> fst in \ + let idx_i = CCList.find_idx ((=)i) l |> CCOption.get_exn |> fst in \ + let idx_j = CCList.find_idx ((=)j) l |> CCOption.get_exn |> fst in \ idx_i > idx_j) \ [ 42, 21; 14, 2; 3, 1; 21, 7; 42, 3] *) diff --git a/src/data/CCIntMap.ml b/src/data/CCIntMap.ml index 3a0cc7e5..35087823 100644 --- a/src/data/CCIntMap.ml +++ b/src/data/CCIntMap.ml @@ -499,7 +499,7 @@ let rec filter_map f m = match m with (*$QR Q.(pair (fun2 Observable.int Observable.int @@ option bool) (small_list (pair int int))) (fun (f,l) -> let QCheck.Fun(_,f) = f in - _list_uniq (CCList.filter_map (fun (x,y) -> CCOpt.map (CCPair.make x) @@ f x y) l) = + _list_uniq (CCList.filter_map (fun (x,y) -> CCOption.map (CCPair.make x) @@ f x y) l) = (_list_uniq @@ to_list @@ filter_map f @@ of_list l) ) *) diff --git a/src/data/CCWBTree.ml b/src/data/CCWBTree.ml index de659897..f0024676 100644 --- a/src/data/CCWBTree.ml +++ b/src/data/CCWBTree.ml @@ -534,7 +534,7 @@ module MakeFull(K : KEY) : S with type key = K.t = struct (*$R let m1 = M.of_list [1, 1; 2, 2; 4, 4] in let m2 = M.of_list [1, 1; 3, 3; 4, 4; 7, 7] in - let m = M.merge ~f:(fun k -> CCOpt.map2 (+)) m1 m2 in + let m = M.merge ~f:(fun k -> CCOption.map2 (+)) m1 m2 in assert_bool "balanced" (M.balanced m); assert_equal ~cmp:(CCList.equal (CCPair.equal CCInt.equal CCInt.equal)) diff --git a/src/data/CCZipper.ml b/src/data/CCZipper.ml index ec7eb143..da89786c 100644 --- a/src/data/CCZipper.ml +++ b/src/data/CCZipper.ml @@ -69,7 +69,7 @@ let focused = function (*$Q zip_gen (fun g -> \ - is_focused g = (focused g |> CCOpt.is_some)) + is_focused g = (focused g |> CCOption.is_some)) *) let focused_exn = function