diff --git a/src/batInnerPervasives.mlv b/src/batInnerPervasives.mlv index c86f1f7ec..7394c6792 100644 --- a/src/batInnerPervasives.mlv +++ b/src/batInnerPervasives.mlv @@ -45,18 +45,18 @@ let unique () = type ('a, 'b) result = | Ok of 'a - | Bad of 'b + | Error of 'b (* Ideas taken from Nicholas Pouillard's my_std.ml in ocamlbuild/ *) let ignore_ok = function Ok _ -> () - | Bad ex -> raise ex + | Error ex -> raise ex let ok = function Ok v -> v - | Bad ex -> raise ex + | Error ex -> raise ex -let wrap f x = try Ok (f x) with ex -> Bad ex +let wrap f x = try Ok (f x) with ex -> Error ex let forever f x = ignore (while true do f x done) diff --git a/src/batParserCo.ml b/src/batParserCo.ml index cac47016a..be2a37596 100644 --- a/src/batParserCo.ml +++ b/src/batParserCo.ml @@ -274,7 +274,7 @@ let lookahead p e = match apply p e with | Failure _ as result -> result let interpret_result = function - | Setback f | Failure f -> BatInnerPervasives.Bad f + | Setback f | Failure f -> BatInnerPervasives.Error f | Success (r, _) | Backtrack (r, _, _) -> BatInnerPervasives.Ok r let suspend : ('a, 'b, 'c) t -> ('a, (unit -> ('b, 'c report) BatInnerPervasives.result), 'c) t = fun s e -> diff --git a/src/batParserCo.mli b/src/batParserCo.mli index bfede519f..72a474be4 100644 --- a/src/batParserCo.mli +++ b/src/batParserCo.mli @@ -149,7 +149,7 @@ val suspend : ('a, 'b, 'c) t -> ('a, (unit -> ('b, 'c report) BatPervasives.resu val run: ('a, 'b, 'c) t -> ('a, 'c) Source.t -> ('b, 'c report) BatPervasives.result (**[run p s] executes parser [p] on source [s]. In case of success, returns [Ok v], where [v] is the return value of [p]. - In case of failure, returns [Bad f], with [f] containing + In case of failure, returns [Error f], with [f] containing details on the parsing error.*) diff --git a/src/batPervasives.mliv b/src/batPervasives.mliv index 9bb1aee09..5e7f66068 100644 --- a/src/batPervasives.mliv +++ b/src/batPervasives.mliv @@ -839,7 +839,7 @@ val print : ?first:string -> ?last:string -> ?sep:string -> ('a BatInnerIO.outp (** This type represents the outcome of a function which has the possibility of failure. Normal results of type ['a] are marked with [Ok], while failure values of type ['b] are marked with - [Bad]. + [Error]. This is intended to be a safer alternative to functions raising exceptions to signal failure. It is safer in that the possibility @@ -848,25 +848,25 @@ val print : ?first:string -> ?last:string -> ?sep:string -> ('a BatInnerIO.outp For more functions related to this type, see the {!BatResult} module. *) -type ('a, 'b) result = ('a, 'b) BatInnerPervasives.result = +type ('a, 'e) result = ('a, 'e) BatInnerPervasives.result = | Ok of 'a - | Bad of 'b + | Error of 'e (** The result of a computation - either an [Ok] with the normal - result or a [Bad] with some value (often an exception) containing + result or a [Error] with some value (often an exception) containing failure information*) val ignore_ok : ('a, exn) result -> unit (** [ignore_ok (f x)] ignores the result of [f x] if it's ok, but - throws the exception contained if [Bad] is returned. *) + throws the exception contained if [Error] is returned. *) val ok : ('a, exn) result -> 'a (** [f x |> ok] unwraps the [Ok] result of [f x] and returns it, or - throws the exception contained if [Bad] is returned. *) + throws the exception contained if [Error] is returned. *) val wrap : ('a -> 'b) -> 'a -> ('b, exn) result (** [wrap f x] wraps a function that would normally throw an exception on failure such that it now returns a result with either the [Ok] - return value or the [Bad] exception. *) + return value or the [Error] exception. *) (** diff --git a/src/batResult.ml b/src/batResult.ml index 3f9ff5498..4ec02a883 100644 --- a/src/batResult.ml +++ b/src/batResult.ml @@ -1,40 +1,81 @@ - -type ('a, 'b) t = ('a, 'b) BatPervasives.result = +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* The OCaml programmers *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +type ('a, 'e) t = ('a, 'e) BatPervasives.result = | Ok of 'a - | Bad of 'b - -let catch f x = try Ok (f x) with e -> Bad e -let catch2 f x y = try Ok (f x y) with e -> Bad e -let catch3 f x y z = try Ok (f x y z) with e -> Bad e + | Error of 'e + +let ok v = Ok v +let error e = Error e +let value r ~default = match r with Ok v -> v | Error _ -> default +let get_ok = function Ok v -> v | Error _ -> invalid_arg "result is Error _" +let get_error = function Error e -> e | Ok _ -> invalid_arg "result is Ok _" +let bind r f = match r with Ok v -> f v | Error _ as e -> e +let join = function Ok r -> r | Error _ as e -> e +let map_error f = function Error e -> Error (f e) | Ok _ as v -> v +let fold ~ok ~error = function Ok v -> ok v | Error e -> error e +let iter f = function Ok v -> f v | Error _ -> () +let iter_error f = function Error e -> f e | Ok _ -> () +let is_error = function Error _ -> true | Ok _ -> false + +let equal ~ok ~error r0 r1 = match r0, r1 with +| Ok v0, Ok v1 -> ok v0 v1 +| Error e0, Error e1 -> error e0 e1 +| _, _ -> false + +let compare ~ok ~error r0 r1 = match r0, r1 with +| Ok v0, Ok v1 -> ok v0 v1 +| Error e0, Error e1 -> error e0 e1 +| Ok _, Error _ -> -1 +| Error _, Ok _ -> 1 + +let to_list = function Ok v -> [v] | Error _ -> [] +let to_seq = function Ok v -> BatSeq.(cons v nil) | Error _ -> BatSeq.nil + +let catch f x = try Ok (f x) with e -> Error e +let catch2 f x y = try Ok (f x y) with e -> Error e +let catch3 f x y z = try Ok (f x y z) with e -> Error e let of_option = function | Some x -> Ok x - | None -> Bad () + | None -> Error () let to_option = function | Ok x -> Some x - | Bad _-> None + | Error _-> None let default def = function | Ok x -> x - | Bad _ -> def + | Error _ -> def let map f = function - | Bad e -> Bad e + | Error e -> Error e | Ok v -> Ok (f v) (*$T map - map succ (Bad (-1)) = (Bad (-1)) - map succ (Bad 0) = (Bad 0) + map succ (Error (-1)) = (Error (-1)) + map succ (Error 0) = (Error 0) map succ (Ok 3) = (Ok 4) *) let map_both f g = function - | Bad e -> Bad (g e) + | Error e -> Error (g e) | Ok v -> Ok (f v) (*$T map_both - map_both succ pred (Bad (-1)) = (Bad (-2)) - map_both succ pred (Bad 0) = (Bad (-1)) - map_both succ pred (Bad 1) = (Bad 0) + map_both succ pred (Error (-1)) = (Error (-2)) + map_both succ pred (Error 0) = (Error (-1)) + map_both succ pred (Error 1) = (Error 0) map_both succ pred (Ok (-1)) = (Ok 0) map_both succ pred (Ok 0) = (Ok 1) map_both succ pred (Ok 1) = (Ok 2) @@ -42,25 +83,25 @@ let map_both f g = function let map_default def f = function | Ok x -> f x - | Bad _ -> def + | Error _ -> def -let is_ok = function Ok _ -> true | Bad _ -> false +let is_ok = function Ok _ -> true | Error _ -> false -let is_bad = function Bad _ -> true | Ok _ -> false +let is_bad = function Error _ -> true | Ok _ -> false -let is_exn e = function Bad exn -> exn = e | Ok _ -> false +let is_exn e = function Error exn -> exn = e | Ok _ -> false -let get = function Ok x -> x | Bad e -> raise e +let get = function Ok x -> x | Error e -> raise e let print print_val oc = function | Ok x -> BatPrintf.fprintf oc "Ok(%a)" print_val x - | Bad e -> BatPrintf.fprintf oc "Bad(%a)" BatPrintexc.print e + | Error e -> BatPrintf.fprintf oc "Error(%a)" BatPrintexc.print e module Monad = struct let bind m k = match m with | Ok x -> k x - | Bad _ as e -> e + | Error _ as e -> e let return x = Ok x diff --git a/src/batResult.mli b/src/batResult.mli index 802ebeb53..2fa1a4fdf 100644 --- a/src/batResult.mli +++ b/src/batResult.mli @@ -1,80 +1,151 @@ (** Monadic results of computations that can raise exceptions *) (** The type of a result. A result is either [Ok x] carrying the - normal return value [x] or is [Bad e] carrying some indication of an + normal return value [x] or is [Error e] carrying some indication of an error. The value associated with a bad result is usually an exception ([exn]) that can be raised. @since 1.0 *) -type ('a, 'b) t = ('a, 'b) BatPervasives.result = Ok of 'a | Bad of 'b +type ('a, 'e) t = ('a, 'e) BatPervasives.result = Ok of 'a | Error of 'e +val ok : 'a -> ('a, 'b) t +(** [ok v] is [Ok v]. + @since NEXT_RELEASE *) + +val error : 'e -> ('a, 'e) t +(** [error e] is [Error e]. + @since NEXT_RELEASE *) + +val value : ('a, 'e) t -> default:'a -> 'a +(** [value r ~default] is [v] if [r] is [Ok v] and [default] otherwise. + @since NEXT_RELEASE *) + +val default: 'a -> ('a, _) t -> 'a +(** [default d r] evaluates to [d] if [r] is [Error] else [x] when [r] is + [Ok x]. + @see 'value' or a slightly different signature. + @since 2.0 *) + +val get_ok : ('a, 'e) t -> 'a +(** [get_ok r] is [v] if [r] is [Ok v] and @raise Invalid_argument + otherwise. + @since NEXT_RELEASE *) + +val get_error : ('a, 'e) t -> 'e +(** [get_error r] is [e] if [r] is [Error e] and @raise Invalid_argument + otherwise. + @since NEXT_RELEASE *) + +val get : ('a, exn) t -> 'a +(** [get (Ok x)] returns [x], and [get (Error e)] raises [e]. This + function is, in a way, the opposite of the [catch] function + @since 2.0 *) + +val catch: ('a -> 'e) -> 'a -> ('e, exn) t (** Execute a function and catch any exception as a result. This function encapsulates code that could throw an exception and returns that exception as a value. - @since 1.0 -*) -val catch: ('a -> 'b) -> 'a -> ('b, exn) t + @since 1.0 *) -(** As [catch] but two parameters. This saves a closure construction - @since 2.0 -*) val catch2: ('a -> 'b -> 'c) -> 'a -> 'b -> ('c, exn) t +(** As [catch] but two parameters. This saves a closure construction + @since 2.0 *) -(** As [catch] but three parameters. This saves a closure construction - @since 2.0 -*) val catch3: ('a -> 'b -> 'c -> 'd) -> 'a -> 'b -> 'c -> ('d, exn) t +(** As [catch] but three parameters. This saves a closure construction + @since 2.0 *) +val bind : ('a, 'e) t -> ('a -> ('b, 'e) t) -> ('b, 'e) t +(** [bind r f] is [f v] if [r] is [Ok v] and [r] if [r] is [Error _]. + @since NEXT_RELEASE *) -(** [get (Ok x)] returns [x], and [get (Bad e)] raises [e]. This - function is, in a way, the opposite of the [catch] function - @since 2.0 -*) -val get : ('a, exn) t -> 'a +val join : (('a, 'e) t, 'e) t -> ('a, 'e) t +(** [join rr] is [r] if [rr] is [Ok r] and [rr] if [rr] is [Error _]. + @since NEXT_RELEASE *) -(** [default d r] evaluates to [d] if [r] is [Bad] else [x] when [r] is - [Ok x] - @since 2.0 -*) -val default: 'a -> ('a, _) t -> 'a +val map : ('a -> 'b) -> ('a, 'e) t -> ('b, 'e) t +(** [map f r] is [Ok (f v)] if [r] is [Ok v] and [r] if [r] is [Error _]. + @since NEXT_RELEASE *) -(** [map f (Ok x)] returns [Ok (f x)] and [map f (Bad e)] returns [Bad e]. - @since 2.6.0 -*) -val map : ('a -> 'b) -> ('a, 'c) t -> ('b, 'c) t +val map_error : ('e -> 'f) -> ('a, 'e) t -> ('a, 'f) t +(** [map_error f r] is [Error (f e)] if [r] is [Error e] and [r] if + [r] is [Ok _]. + @since NEXT_RELEASE *) -(** [map_both f g (Ok x)] returns [Ok (f x)] and [map_both f g (Bad e)] returns [Bad (g e)]. - @since 2.6.0 -*) val map_both : ('a1 -> 'a2) -> ('b1 -> 'b2) -> ('a1, 'b1) t -> ('a2, 'b2) t +(** [map_both f g (Ok x)] returns [Ok (f x)] and [map_both f g (Error e)] returns [Error (g e)]. + @since 2.6.0 *) -(** [map_default d f r] evaluates to [d] if [r] is [Bad] else [f x] - when [r] is [Ok x] - @since 2.0 -*) val map_default : 'b -> ('a -> 'b) -> ('a, _) t -> 'b +(** [map_default d f r] evaluates to [d] if [r] is [Error] else [f x] + when [r] is [Ok x] + @since 2.0 *) + +val fold : ok:('a -> 'c) -> error:('e -> 'c) -> ('a, 'e) t -> 'c +(** [fold ~ok ~error r] is [ok v] if [r] is [Ok v] and [error e] if [r] + is [Error e]. + @since NEXT_RELEASE *) + +val iter : ('a -> unit) -> ('a, 'e) t -> unit +(** [iter f r] is [f v] if [r] is [Ok v] and [()] otherwise. + @since NEXT_RELEASE *) +val iter_error : ('e -> unit) -> ('a, 'e) t -> unit +(** [iter_error f r] is [f e] if [r] is [Error e] and [()] otherwise. + @since NEXT_RELEASE *) + +(** {1:preds Predicates and comparisons} *) + +val is_ok : ('a, 'e) t -> bool (** [is_ok (Ok _)] is [true], otherwise [false]. - @since 2.0 -*) -val is_ok : ('a, 'b) t -> bool + @since 2.0 *) -(** [is_bad (Bad _)] is [true], otherwise [false] - @since 2.0 -*) -val is_bad : ('a, 'b) t -> bool +val is_error : ('a, 'e) t -> bool +(** [is_error r] is [true] iff [r] is [Error _]. + @since NEXT_RELEASE *) + +val is_bad : ('a, 'e) t -> bool +(** Same as [is_error]. + @since 2.0 *) -(** [is_exn e1 r] is [true] iff [r] is [Bad e2] with [e1=e2] *) +(** [is_exn e1 r] is [true] iff [r] is [Error e2] with [e1=e2] *) val is_exn : exn -> ('a, exn) t -> bool -(** Convert an [option] to a [result] +val equal : + ok:('a -> 'a -> bool) -> error:('e -> 'e -> bool) -> ('a, 'e) t -> + ('a, 'e) t -> bool +(** [equal ~ok ~error r0 r1] tests equality of [r0] and [r1] using [ok] + and [error] to respectively compare values wrapped by [Ok _] and + [Error _]. + @since NEXT_RELEASE *) + +val compare : + ok:('a -> 'a -> int) -> error:('e -> 'e -> int) -> ('a, 'e) t -> + ('a, 'e) t -> int +(** [compare ~ok ~error r0 r1] totally orders [r0] and [r1] using [ok] and + [error] to respectively compare values wrapped by [Ok _ ] and [Error _]. + [Ok _] values are smaller than [Error _] values. + @since NEXT_RELEASE *) + +(** {1:convert Converting} *) + +val to_option : ('a, _) t -> 'a option +(** [to_option r] is [r] as an option, mapping [Ok v] to [Some v] and + [Error _] to [None]. @since 1.0 *) -val of_option: 'a option -> ('a, unit) t -(** Convert a [result] to an [option] +val of_option: 'a option -> ('a, unit) t +(** Convert an [option] to a [result] @since 1.0 *) -val to_option: ('a, _) t -> 'a option +val to_list : ('a, 'e) t -> 'a list +(** [to_list r] is [[v]] if [r] is [Ok v] and [[]] otherwise. + @since NEXT_RELEASE *) + +val to_seq : ('a, 'e) t -> 'a BatSeq.t +(** [to_seq r] is [r] as a sequence. [Ok v] is the singleton sequence + containing [v] and [Error _] is the empty sequence. + @since NEXT_RELEASE *) (** {6 The Result Monad} *) @@ -90,10 +161,10 @@ module Monad : sig [r] is an error. @since 2.0 *) - val bind: ('a, 'b) t -> ('a -> ('c, 'b) t) -> ('c, 'b) t + val bind: ('a, 'e) t -> ('a -> ('c, 'e) t) -> ('c, 'e) t (** as [bind] *) - val ( >>= ): ('a, 'b) t -> ('a -> ('c, 'b) t) -> ('c, 'b) t + val ( >>= ): ('a, 'e) t -> ('a -> ('c, 'e) t) -> ('c, 'e) t (** Monadic return, just encapsulates the given value with Ok *) val return : 'a -> ('a, _) t @@ -103,8 +174,8 @@ end (** This infix module provides the operator [(>>=)] *) module Infix : sig - val ( >>= ): ('a, 'b) t -> ('a -> ('c, 'b) t) -> ('c, 'b) t + val ( >>= ): ('a, 'e) t -> ('a -> ('c, 'e) t) -> ('c, 'e) t end -(** Print a result as Ok(x) or Bad(exn) *) +(** Print a result as Ok(x) or Error(exn) *) val print : ('b BatInnerIO.output -> 'a -> unit) -> 'b BatInnerIO.output -> ('a, exn) t -> unit