From 302dba6cb5b1e29e92f433413b7bce77e4e442f7 Mon Sep 17 00:00:00 2001 From: Fardale Date: Wed, 22 Sep 2021 23:03:19 +0200 Subject: [PATCH] chore(CCOption): rename CCOpt to CCOption and deprecate CCOpt In the stdlib the module associated with the option type is called Option and in containers it was called CCOpt. Renaming CCOpt to CCOption make the name of containers module uniforme with respect to the stdlib. --- README.md | 2 +- src/core/CCList.ml | 2 +- src/core/CCList.mli | 4 +- src/core/CCListLabels.mli | 4 +- src/core/CCMap.ml | 2 +- src/core/CCOpt.ml | 270 +---------------------------------- src/core/CCOpt.mli | 251 +------------------------------- src/core/CCOption.ml | 269 ++++++++++++++++++++++++++++++++++ src/core/CCOption.mli | 250 ++++++++++++++++++++++++++++++++ src/core/CCResult.mli | 2 +- src/core/CCVector.ml | 2 +- src/core/containers.ml | 2 +- src/core/containersLabels.ml | 2 +- src/data/CCGraph.ml | 8 +- src/data/CCIntMap.ml | 2 +- src/data/CCWBTree.ml | 2 +- src/data/CCZipper.ml | 2 +- 17 files changed, 540 insertions(+), 536 deletions(-) create mode 100644 src/core/CCOption.ml create mode 100644 src/core/CCOption.mli 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