From badd9709685dcd70b05cb6729de96926dcda5a05 Mon Sep 17 00:00:00 2001
From: Francois Berenger <unixjunkie@sdf.org>
Date: Mon, 19 Aug 2019 17:13:06 +0900
Subject: [PATCH 01/11] repaired upload-docs target in Makefile

and make it more readable too
---
 Makefile | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index ddd86a52..d7752f42 100644
--- a/Makefile
+++ b/Makefile
@@ -288,4 +288,13 @@ setup.ml: _oasis
 
 # uploads the current documentation to github hdoc2/ directory
 upload-docs:
-	make doc && git checkout gh-pages && rm -f hdoc2/*.html && cp _build/batteries.docdir/*.html hdoc2/ && git add hdoc2/*.html && git commit -a -m"Update to latest documentation" && git push github gh-pages
+	make doc && \
+	rm -rf /tmp/batteries.docdir && \
+	cp -a _build/batteries.docdir /tmp/ && \
+	git checkout gh-pages && \
+	rm -f hdoc2/*.html && \
+	cp /tmp/batteries.docdir/*.html hdoc2/ && \
+	git add hdoc2/*.html && \
+	git commit hdoc2 -m "Update ocamldoc to latest release" && \
+	git push \
+	git@github.com:ocaml-batteries-team/batteries-included.git gh-pages

From 613a336c91acc1cad1efefcefaf9fbab2b29eb4f Mon Sep 17 00:00:00 2001
From: Francois Berenger <unixjunkie@sdf.org>
Date: Mon, 19 Aug 2019 17:15:37 +0900
Subject: [PATCH 02/11] start of next release

---
 ChangeLog | 4 ++++
 _oasis    | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index afa8d537..240f0ec9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,10 @@
 Changelog
 ---------
 
+## NEXT_RELEASE
+
+... cool features to come.
+
 ## v2.10.0 (minor release)
 
 This minor release adds support for OCaml 4.08.0.
diff --git a/_oasis b/_oasis
index 11fedd39..70aa351b 100644
--- a/_oasis
+++ b/_oasis
@@ -1,7 +1,7 @@
 OASISFormat:  0.4
 OCamlVersion: >= 3.12.1
 Name:         batteries
-Version:      2.10.0
+Version:      NEXT_RELEASE
 Authors:      Batteries Included Team
 License:      LGPL-2.1 with OCaml linking exception
 LicenseFile:  LICENSE

From 9d3ab53cc06f2aee0920c6b350b3c297d00f0370 Mon Sep 17 00:00:00 2001
From: Cedric Cellier <rixed@happyleptic.org>
Date: Fri, 27 Sep 2019 10:16:09 +0200
Subject: [PATCH 03/11] Fix compilation by BER MetaOCaml (#909)

Set.Infix used to have operators `<.` and `>.` (for strict
subset and strict superset), but `>.` is also used as a code
block end-quote by BER.

It's been decided to jettison the whole BatSet.Infix module,
as a simple and future proof fix.

Ref #908
---
 src/batSet.ml  | 43 -------------------------------------------
 src/batSet.mli | 39 ---------------------------------------
 2 files changed, 82 deletions(-)

diff --git a/src/batSet.ml b/src/batSet.ml
index 01a58bf2..f1b07122 100644
--- a/src/batSet.ml
+++ b/src/batSet.ml
@@ -586,16 +586,6 @@ sig
   val print :  ?first:string -> ?last:string -> ?sep:string ->
     ('a BatInnerIO.output -> elt -> unit) ->
     'a BatInnerIO.output -> t -> unit
-  module Infix : sig
-    val (<--) : t -> elt -> t (** insertion *)
-    val (<.) : t -> t -> bool  (** strict subset *)
-    val (>.) : t -> t -> bool  (** strict superset *)
-    val (<=.) : t -> t -> bool (** subset *)
-    val (>=.) : t -> t -> bool (** superset *)
-    val (-.) : t -> t -> t     (** difference *)
-    val (&&.) : t -> t -> t   (** intersection *)
-    val (||.) : t -> t -> t   (** union *)
-  end
   (** Operations on {!Set} without exceptions.*)
   module Exceptionless : sig
     val min_elt: t -> elt option
@@ -727,17 +717,6 @@ struct
   let print ?first ?last ?sep print_elt out t =
     Concrete.print ?first ?last ?sep print_elt out (impl_of_t t)
 
-  module Infix = struct
-    let (<--) s x = add x s
-    let (<.) a b = not (equal a b) && subset a b
-    let (>.) a b = not (equal a b) && subset b a
-    let (<=.) = subset
-    let (>=.) a b = subset b a
-    let (-.) = diff
-    let (&&.) = inter
-    let (||.) = union
-  end
-
   module Exceptionless =
   struct
     let min_elt t = try Some (min_elt t) with Not_found -> None
@@ -882,17 +861,6 @@ module PSet = struct (*$< PSet *)
   let equal s1 s2 = Concrete.equal s1.cmp s1.set s2.set
   let subset s1 s2 = Concrete.subset s1.cmp s1.set s2.set
   let disjoint s1 s2 = Concrete.disjoint s1.cmp s1.set s2.set
-
-  module Infix = struct
-    let (<--) s x = add x s
-    let (<.) a b = not (equal a b) && subset a b
-    let (>.) a b = not (equal a b) && subset b a
-    let (<=.) = subset
-    let (>=.) a b = subset b a
-    let (-.) = diff
-    let (&&.) = intersect
-    let (||.) = union
-  end
 end (*$>*)
 
 type 'a t = 'a Concrete.set
@@ -1083,17 +1051,6 @@ let disjoint s1 s2 = Concrete.disjoint Pervasives.compare s1 s2
 
 *)
 
-module Infix = struct
-  let (<--) s x = add x s
-  let (<.) a b = not (equal a b) && subset a b
-  let (>.) a b = not (equal a b) && subset b a
-  let (<=.) = subset
-  let (>=.) a b = subset b a
-  let (-.) = diff
-  let (&&.) = intersect
-  let (||.) = union
-end
-
 module Incubator = struct (*$< Incubator *)
   let op_map f s = Concrete.op_map f s
     (*$T op_map
diff --git a/src/batSet.mli b/src/batSet.mli
index 8b8dfdd2..3cd62dec 100644
--- a/src/batSet.mli
+++ b/src/batSet.mli
@@ -301,19 +301,6 @@ sig
     ('a BatInnerIO.output -> elt -> unit) ->
     'a BatInnerIO.output -> t -> unit
 
-  (** {7 Infix operators} *)
-
-  module Infix : sig
-    val (<--) : t -> elt -> t (** insertion *)
-    val (<.) : t -> t -> bool  (** strict subset *)
-    val (>.) : t -> t -> bool  (** strict superset *)
-    val (<=.) : t -> t -> bool (** subset *)
-    val (>=.) : t -> t -> bool (** superset *)
-    val (-.) : t -> t -> t     (** difference *)
-    val (&&.) : t -> t -> t   (** intersection *)
-    val (||.) : t -> t -> t   (** union *)
-  end
-
   (** {6 Override modules}*)
 
   (**
@@ -667,19 +654,6 @@ val print :  ?first:string -> ?last:string -> ?sep:string ->
   ('a BatInnerIO.output -> 'c -> unit) ->
   'a BatInnerIO.output -> 'c t -> unit
 
-(** {7 Infix operators} *)
-
-module Infix : sig
-  val (<--) : 'a t -> 'a -> 'a t (** insertion *)
-  val (<.) : 'a t -> 'a t -> bool  (** strict subset *)
-  val (>.) : 'a t -> 'a t -> bool  (** strict superset *)
-  val (<=.) : 'a t -> 'a t -> bool (** subset *)
-  val (>=.) : 'a t -> 'a t -> bool (** superset *)
-  val (-.) : 'a t -> 'a t -> 'a t     (** difference *)
-  val (&&.) : 'a t -> 'a t -> 'a t   (** intersection *)
-  val (||.) : 'a t -> 'a t -> 'a t   (** union *)
-end
-
 (** {6 Incubator} *)
 module Incubator : sig
 
@@ -958,19 +932,6 @@ module PSet : sig
     ('a BatInnerIO.output -> 'c -> unit) ->
     'a BatInnerIO.output -> 'c t -> unit
 
-  (** {7 Infix operators} *)
-
-  module Infix : sig
-    val (<--) : 'a t -> 'a -> 'a t (** insertion *)
-    val (<.) : 'a t -> 'a t -> bool  (** strict subset *)
-    val (>.) : 'a t -> 'a t -> bool  (** strict superset *)
-    val (<=.) : 'a t -> 'a t -> bool (** subset *)
-    val (>=.) : 'a t -> 'a t -> bool (** superset *)
-    val (-.) : 'a t -> 'a t -> 'a t     (** difference *)
-    val (&&.) : 'a t -> 'a t -> 'a t   (** intersection *)
-    val (||.) : 'a t -> 'a t -> 'a t   (** union *)
-  end
-
   (** get the comparison function used for a polymorphic map *)
   val get_cmp : 'a t -> ('a -> 'a -> int)
 

From 549a0f9a460f1b84a9efce3f965cfa3ed75abc22 Mon Sep 17 00:00:00 2001
From: Cedric Cellier <rixed@happyleptic.org>
Date: Mon, 30 Sep 2019 04:39:59 +0200
Subject: [PATCH 04/11] Add BatFilename (#910)

Also added `Filename.split_extension`

Closes #445
---
 .gitignore           |   1 +
 src/batFilename.ml   |  33 ++++++
 src/batFilename.mliv | 234 +++++++++++++++++++++++++++++++++++++++++++
 src/batteries.mllib  |   1 +
 src/batteries.mlv    |   1 +
 5 files changed, 270 insertions(+)
 create mode 100644 src/batFilename.ml
 create mode 100644 src/batFilename.mliv

diff --git a/.gitignore b/.gitignore
index 3b6a1306..230f587a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,3 +34,4 @@ src/batPrintf.mli
 src/batFormat.mli
 src/batSys.mli
 src/batBigarray.mli
+src/batFilename.mli
diff --git a/src/batFilename.ml b/src/batFilename.ml
new file mode 100644
index 00000000..82c2e1b1
--- /dev/null
+++ b/src/batFilename.ml
@@ -0,0 +1,33 @@
+(*
+ * BatFilename - Extended Filename module
+ * Copyright (C) 1996 Xavier Leroy
+ *               2008 David Teller, LIFO, Universite d'Orleans
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version,
+ * with the special exception on linking described in file LICENSE.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *)
+
+include Filename
+
+let split_extension s =
+  remove_extension s, extension s
+
+(*$= split_extension & ~printer:(IO.to_string (Tuple2.print String.print String.print))
+  ("/foo/bar", ".baz") (split_extension "/foo/bar.baz")
+  ("/foo/bar", "")    (split_extension "/foo/bar")
+  ("/foo/bar", ".")   (split_extension "/foo/bar.")
+  ("/foo/.rc", "")    (split_extension "/foo/.rc")
+  ("", "")            (split_extension "")
+*)
diff --git a/src/batFilename.mliv b/src/batFilename.mliv
new file mode 100644
index 00000000..0bcec2e3
--- /dev/null
+++ b/src/batFilename.mliv
@@ -0,0 +1,234 @@
+(*
+ * BatFilename - Extended Filename module
+ * Copyright (C) 1996 Xavier Leroy
+ *               2008 David Teller
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version,
+ * with the special exception on linking described in file LICENSE.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *)
+
+(** Operations on file names. *)
+
+val current_dir_name : string
+(** The conventional name for the current directory (e.g. [.] in Unix). *)
+
+val parent_dir_name : string
+(** The conventional name for the parent of the current directory
+   (e.g. [..] in Unix). *)
+
+val dir_sep : string
+(** The directory separator (e.g. [/] in Unix).
+   @since NEXT_RELEASE and OCaml 3.11.2 *)
+
+val concat : string -> string -> string
+(** [concat dir file] returns a file name that designates file
+   [file] in directory [dir]. *)
+
+val is_relative : string -> bool
+(** Return [true] if the file name is relative to the current
+   directory, [false] if it is absolute (i.e. in Unix, starts
+   with [/]). *)
+
+val is_implicit : string -> bool
+(** Return [true] if the file name is relative and does not start
+   with an explicit reference to the current directory ([./] or
+   [../] in Unix), [false] if it starts with an explicit reference
+   to the root directory or the current directory. *)
+
+val check_suffix : string -> string -> bool
+(** [check_suffix name suff] returns [true] if the filename [name]
+    ends with the suffix [suff].
+
+    Under Windows ports (including Cygwin), comparison is
+    case-insensitive, relying on [String.lowercase_ascii].  Note that
+    this does not match exactly the interpretation of case-insensitive
+    filename equivalence from Windows.  *)
+
+val chop_suffix : string -> string -> string
+(** [chop_suffix name suff] removes the suffix [suff] from
+   the filename [name]. The behavior is undefined if [name] does not
+   end with the suffix [suff]. [chop_suffix_opt] is thus recommended
+   instead.
+*)
+
+##V>=4.8##val chop_suffix_opt: suffix:string -> string -> string option
+##V>=4.8##(** [chop_suffix_opt ~suffix filename] removes the suffix from
+##V>=4.8##    the [filename] if possible, or returns [None] if the
+##V>=4.8##    filename does not end with the suffix.
+##V>=4.8##
+##V>=4.8##    Under Windows ports (including Cygwin), comparison is
+##V>=4.8##    case-insensitive, relying on [String.lowercase_ascii].  Note that
+##V>=4.8##    this does not match exactly the interpretation of case-insensitive
+##V>=4.8##    filename equivalence from Windows.
+##V>=4.8##
+##V>=4.8##    @since NEXT_RELEASE and OCaml 4.08
+##V>=4.8##*)
+
+
+##V>=4.4##val extension : string -> string
+##V>=4.4##(** [extension name] is the shortest suffix [ext] of [name0] where:
+##V>=4.4##
+##V>=4.4##    - [name0] is the longest suffix of [name] that does not
+##V>=4.4##      contain a directory separator;
+##V>=4.4##    - [ext] starts with a period;
+##V>=4.4##    - [ext] is preceded by at least one non-period character
+##V>=4.4##      in [name0].
+##V>=4.4##
+##V>=4.4##    If such a suffix does not exist, [extension name] is the empty
+##V>=4.4##    string.
+##V>=4.4##
+##V>=4.4##    @since NEXT_RELEASE and OCaml 4.04
+##V>=4.4##*)
+
+##V>=4.4##val remove_extension : string -> string
+##V>=4.4##(** Return the given file name without its extension, as defined
+##V>=4.4##    in {!Filename.extension}. If the extension is empty, the function
+##V>=4.4##    returns the given file name.
+##V>=4.4##
+##V>=4.4##    The following invariant holds for any file name [s]:
+##V>=4.4##
+##V>=4.4##    [remove_extension s ^ extension s = s]
+##V>=4.4##
+##V>=4.4##    @since NEXT_RELEASE and OCaml 4.04
+##V>=4.4##*)
+
+val chop_extension : string -> string
+(** Same as {!Filename.remove_extension}, but raise [Invalid_argument]
+    if the given name has an empty extension. *)
+
+
+val basename : string -> string
+(** Split a file name into directory name / base file name.
+   If [name] is a valid file name, then [concat (dirname name) (basename name)]
+   returns a file name which is equivalent to [name]. Moreover,
+   after setting the current directory to [dirname name] (with {!Sys.chdir}),
+   references to [basename name] (which is a relative file name)
+   designate the same file as [name] before the call to {!Sys.chdir}.
+
+   This function conforms to the specification of POSIX.1-2008 for the
+   [basename] utility. *)
+
+val dirname : string -> string
+(** See {!Filename.basename}.
+   This function conforms to the specification of POSIX.1-2008 for the
+   [dirname] utility. *)
+
+val temp_file : ?temp_dir: string -> string -> string -> string
+(** [temp_file prefix suffix] returns the name of a
+   fresh temporary file in the temporary directory.
+   The base name of the temporary file is formed by concatenating
+   [prefix], then a suitably chosen integer number, then [suffix].
+   The optional argument [temp_dir] indicates the temporary directory
+   to use, defaulting to the current result of {!Filename.get_temp_dir_name}.
+   The temporary file is created empty, with permissions [0o600]
+   (readable and writable only by the file owner).  The file is
+   guaranteed to be different from any other file that existed when
+   [temp_file] was called.
+   Raise [Sys_error] if the file could not be created.
+   @before 3.11.2 no ?temp_dir optional argument
+*)
+
+val open_temp_file :
+      ?mode: open_flag list -> ?perms: int -> ?temp_dir: string -> string ->
+      string -> string * out_channel
+(** Same as {!Filename.temp_file}, but returns both the name of a fresh
+   temporary file, and an output channel opened (atomically) on
+   this file.  This function is more secure than [temp_file]: there
+   is no risk that the temporary file will be modified (e.g. replaced
+   by a symbolic link) before the program opens it.  The optional argument
+   [mode] is a list of additional flags to control the opening of the file.
+   It can contain one or several of [Open_append], [Open_binary],
+   and [Open_text].  The default is [[Open_text]] (open in text mode). The
+   file is created with permissions [perms] (defaults to readable and
+   writable only by the file owner, [0o600]).
+
+   @raise Sys_error if the file could not be opened.
+   @before 4.03.0 no ?perms optional argument
+   @before 3.11.2 no ?temp_dir optional argument
+*)
+
+##V>=4.0##val get_temp_dir_name : unit -> string
+##V>=4.0##(** The name of the temporary directory:
+##V>=4.0##    Under Unix, the value of the [TMPDIR] environment variable, or "/tmp"
+##V>=4.0##    if the variable is not set.
+##V>=4.0##    Under Windows, the value of the [TEMP] environment variable, or "."
+##V>=4.0##    if the variable is not set.
+##V>=4.0##    The temporary directory can be changed with {!Filename.set_temp_dir_name}.
+##V>=4.0##    @since NEXT_RELEASE and OCaml 4.00.0
+##V>=4.0##*)
+
+##V>=4.0##val set_temp_dir_name : string -> unit
+##V>=4.0##(** Change the temporary directory returned by {!Filename.get_temp_dir_name}
+##V>=4.0##    and used by {!Filename.temp_file} and {!Filename.open_temp_file}.
+##V>=4.0##    @since NEXT_RELEASE and OCaml 4.00.0
+##V>=4.0##*)
+
+val temp_dir_name : string
+  [@@ocaml.deprecated "Use Filename.get_temp_dir_name instead"]
+(** The name of the initial temporary directory:
+    Under Unix, the value of the [TMPDIR] environment variable, or "/tmp"
+    if the variable is not set.
+    Under Windows, the value of the [TEMP] environment variable, or "."
+    if the variable is not set.
+    @deprecated You should use {!Filename.get_temp_dir_name} instead.
+    @since NEXT_RELEASE and OCaml 3.09.1
+*)
+
+val quote : string -> string
+(** Return a quoted version of a file name, suitable for use as
+    one argument in a command line, escaping all meta-characters.
+    Warning: under Windows, the output is only suitable for use
+    with programs that follow the standard Windows quoting
+    conventions.
+ *)
+
+##V>4.9##val quote_command :
+##V>4.9##       string -> ?stdin:string -> ?stdout:string -> ?stderr:string
+##V>4.9##              -> string list -> string
+##V>4.9##(** [quote_command cmd args] returns a quoted command line, suitable
+##V>4.9##    for use as an argument to {!Sys.command}, {!Unix.system}, and the
+##V>4.9##    {!Unix.open_process} functions.
+##V>4.9##
+##V>4.9##    The string [cmd] is the command to call.  The list [args] is
+##V>4.9##    the list of arguments to pass to this command.  It can be empty.
+##V>4.9##
+##V>4.9##    The optional arguments [?stdin] and [?stdout] and [?stderr] are
+##V>4.9##    file names used to redirect the standard input, the standard
+##V>4.9##    output, or the standard error of the command.
+##V>4.9##    If [~stdin:f] is given, a redirection [< f] is performed and the
+##V>4.9##    standard input of the command reads from file [f].
+##V>4.9##    If [~stdout:f] is given, a redirection [> f] is performed and the
+##V>4.9##    standard output of the command is written to file [f].
+##V>4.9##    If [~stderr:f] is given, a redirection [2> f] is performed and the
+##V>4.9##    standard error of the command is written to file [f].
+##V>4.9##    If both [~stdout:f] and [~stderr:f] are given, with the exact
+##V>4.9##    same file name [f], a [2>&1] redirection is performed so that the
+##V>4.9##    standard output and the standard error of the command are interleaved
+##V>4.9##    and redirected to the same file [f].
+##V>4.9##
+##V>4.9##    Under Unix and Cygwin, the command, the arguments, and the redirections
+##V>4.9##    if any are quoted using {!Filename.quote}, then concatenated.
+##V>4.9##    Under Win32, additional quoting is performed as required by the
+##V>4.9##    [cmd.exe] shell that is called by {!Sys.command}.
+##V>4.9##
+##V>4.9##    Raise [Failure] if the command cannot be escaped on the current platform.
+##V>4.9##*)
+
+val split_extension : string -> string * string
+(** [split_extension s] returns both the filename [s] without its extension
+    and its extension in two distinct strings.
+    For instance, [split_extension "foo.bar"] returns the pair ["foo",".bar"].
+
+    @since NEXT_RELEASE *)
diff --git a/src/batteries.mllib b/src/batteries.mllib
index 30ab679a..cd4df595 100644
--- a/src/batteries.mllib
+++ b/src/batteries.mllib
@@ -13,6 +13,7 @@ BatInnerPervasives
   BatDeque
   BatDigest
   BatEnum
+  BatFilename
   BatFingerTree
   BatFloat
   BatFormat
diff --git a/src/batteries.mlv b/src/batteries.mlv
index e4c6e699..81047a89 100644
--- a/src/batteries.mlv
+++ b/src/batteries.mlv
@@ -162,6 +162,7 @@ module Int = BatInt
 module Bool = BatBool
 module Unit = BatUnit
 (*module Int63 = BatInt63*)
+module Filename = BatFilename
 
 (* Modules in-progress, API stability not guaranteed *)
 module Incubator = struct

From 4d34e6aa3973a905240c4dd43d0ed619445c9351 Mon Sep 17 00:00:00 2001
From: Cedric Cellier <rixed@happyleptic.org>
Date: Mon, 30 Sep 2019 04:41:06 +0200
Subject: [PATCH 05/11] s/RELASE/RELEASE (#911)

typos
---
 src/batGc.mliv       | 2 +-
 src/batPrintexc.mliv | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/batGc.mliv b/src/batGc.mliv
index 906739ab..de5554e9 100644
--- a/src/batGc.mliv
+++ b/src/batGc.mliv
@@ -356,7 +356,7 @@ val finalise : ('a -> unit) -> 'a -> unit
 ##V>=4.4##    finalisation function attached with `GC.finalise` are always
 ##V>=4.4##    called before the finalisation function attached with `GC.finalise_last`.
 ##V>=4.4##
-##V>=4.4##    @since NEXT_RELASE and OCaml 4.04
+##V>=4.4##    @since NEXT_RELEASE and OCaml 4.04
 ##V>=4.4##*)
 
 val finalise_release : unit -> unit;;
diff --git a/src/batPrintexc.mliv b/src/batPrintexc.mliv
index cd6246f9..2ea7f3bf 100644
--- a/src/batPrintexc.mliv
+++ b/src/batPrintexc.mliv
@@ -325,7 +325,7 @@ val print : _ BatInnerIO.output -> exn -> unit
 ##V>=4.4##    raw_backtrace_slot -> raw_backtrace_slot option
 ##V>=4.4##(** [get_raw_backtrace_next_slot slot] returns the next slot inlined, if any.
 ##V>=4.4##
-##V>=4.4##    @since NEXT_RELASE and OCaml 4.04
+##V>=4.4##    @since NEXT_RELEASE and OCaml 4.04
 ##V>=4.4##*)
 
 

From 9cdd373c9f785e399eaeec73168d1aab615247e4 Mon Sep 17 00:00:00 2001
From: Cedric Cellier <rixed@happyleptic.org>
Date: Mon, 30 Sep 2019 04:45:14 +0200
Subject: [PATCH 06/11] Improve toplevel printability of predefined sets (#912)

Redefining the modules (instead of using those predefined
in BatSet) was causing the printers for BatSet.Int and friends
useless.

Closes #750
---
 battop.ml             |  4 ++++
 src/batteriesPrint.ml | 15 +++++++--------
 2 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/battop.ml b/battop.ml
index 2900ccc1..397f5583 100644
--- a/battop.ml
+++ b/battop.ml
@@ -72,6 +72,10 @@ open Batteries;;
 #install_printer BatteriesPrint.char_dynarray;;
 #install_printer BatteriesPrint.float_dynarray;;
 #install_printer BatteriesPrint.int_set;;
+#install_printer BatteriesPrint.int32_set;;
+#install_printer BatteriesPrint.int64_set;;
+#install_printer BatteriesPrint.natint_set;;
+#install_printer BatteriesPrint.float_set;;
 #install_printer BatteriesPrint.string_set;;
 #install_printer BatteriesPrint.int_pset;;
 #install_printer BatteriesPrint.string_pset;;
diff --git a/src/batteriesPrint.ml b/src/batteriesPrint.ml
index 35e4f98d..24f396b8 100644
--- a/src/batteriesPrint.ml
+++ b/src/batteriesPrint.ml
@@ -42,14 +42,13 @@ let int_dynarray = BatIO.to_f_printer (BatDynArray.print BatInt.print)
 let char_dynarray = BatIO.to_f_printer (BatDynArray.print BatChar.print)
 let float_dynarray = BatIO.to_f_printer (BatDynArray.print BatFloat.print)
 
-module IntSet = BatSet.Make(BatInt)
-let int_set = BatIO.to_f_printer (IntSet.print BatInt.print)
-module StringSet = BatSet.Make(String)
-let string_set = BatIO.to_f_printer (StringSet.print BatString.print)
-module TextSet = BatSet.Make(BatText)
-let text_set = BatIO.to_f_printer (TextSet.print BatText.print)
-(*module CharSet = BatSet.Make(BatChar)
-  let char_set = BatIO.to_f_printer (CharSet.print BatChar.print) *)
+let int_set = BatIO.to_f_printer (BatSet.Int.print BatInt.print)
+let int32_set = BatIO.to_f_printer (BatSet.Int32.print BatInt32.print)
+let int64_set = BatIO.to_f_printer (BatSet.Int64.print BatInt64.print)
+let natint_set = BatIO.to_f_printer (BatSet.Nativeint.print BatNativeint.print)
+let float_set = BatIO.to_f_printer (BatSet.Float.print BatFloat.print)
+let char_set = BatIO.to_f_printer (BatSet.Char.print BatChar.print)
+let string_set = BatIO.to_f_printer (BatSet.String.print BatString.print)
 
 let int_pset = BatIO.to_f_printer (BatSet.print BatInt.print)
 let string_pset = BatIO.to_f_printer (BatSet.print BatString.print)

From f8aef1e91f3b20b52e01a939b8500addc7bfc891 Mon Sep 17 00:00:00 2001
From: Cedric Cellier <rixed@happyleptic.org>
Date: Mon, 30 Sep 2019 05:01:27 +0200
Subject: [PATCH 07/11] Remove BatOo (#915)

As it is undocumented, unsupported and unsafe.

Closes #848
---
 build/intro.text    |   2 +-
 src/batOo.ml        |  24 ------
 src/batOo.mli       | 190 --------------------------------------------
 src/batteries.mllib |   1 -
 src/batteries.mlv   |   1 -
 5 files changed, 1 insertion(+), 217 deletions(-)
 delete mode 100644 src/batOo.ml
 delete mode 100644 src/batOo.mli

diff --git a/build/intro.text b/build/intro.text
index 22b71a0b..319edcfb 100644
--- a/build/intro.text
+++ b/build/intro.text
@@ -55,7 +55,7 @@ These modules have base library equivalents.  When using [open Batteries], [BatF
 
 {!modules: BatArray BatBigarray BatBig_int BatBuffer BatComplex
 BatDigest BatFormat BatGc BatGenlex BatHashtbl BatLexing BatList
-BatMap BatMarshal BatNum BatOo BatPervasives BatPrintexc BatPrintf
+BatMap BatMarshal BatNum BatPervasives BatPrintexc BatPrintf
 BatQueue BatRandom BatScanf BatSet BatStack BatStream BatString
 BatSys BatUnix}
 
diff --git a/src/batOo.ml b/src/batOo.ml
deleted file mode 100644
index 48844cd0..00000000
--- a/src/batOo.ml
+++ /dev/null
@@ -1,24 +0,0 @@
-(*
- * BatOO - Extended operations on objects
- * Copyright (C) 1996 Jerome Vouillon, INRIA
- *               2008 David Teller, LIFO, Universite d'Orleans
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version,
- * with the special exception on linking described in file LICENSE.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *)
-
-
-include Oo
-module Internal = CamlinternalOO
diff --git a/src/batOo.mli b/src/batOo.mli
deleted file mode 100644
index 7512ddbd..00000000
--- a/src/batOo.mli
+++ /dev/null
@@ -1,190 +0,0 @@
-(*
- * BatOO - Extended operations on objects
- * Copyright (C) 1996 Jerome Vouillon, INRIA
- *               2008 David Teller, LIFO, Universite d'Orleans
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version,
- * with the special exception on linking described in file LICENSE.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *)
-
-(** Operations on objects
-
-    @author Jerome Vouillon (Base module)
-    @author David Teller (integration to Batteries)
-*)
-
-val copy : (< .. > as 'a) -> 'a
-(** [Oo.copy o] returns a copy of object [o], that is a fresh
-    object with the same methods and instance variables as [o]  *)
-
-external id : < .. > -> int = "%field1"
-(** Return an integer identifying this object, unique for
-    the current execution of the program. *)
-
-(**/**)
-(** For internal use (CamlIDL) *)
-
-val new_method :          string -> CamlinternalOO.tag(**As {!Internal.public_method_label}*)
-val public_method_label : string -> CamlinternalOO.tag(**As {!Internal.public_method_label}*)
-
-(**/**)
-
-module Internal:
-sig
-
-  (** Run-time support for objects and classes.
-      All functions in this module are for system use only, not for the
-      casual user.
-
-      @documents CamlinternalOO
-  *)
-
-  (** {6 Classes} *)
-
-  type tag     = CamlinternalOO.tag
-  type label   = CamlinternalOO.label
-  type table   = CamlinternalOO.table  (**Internal representation of the vtable, i.e. the table of virtual methods.*)
-  type meth    = CamlinternalOO.meth
-  type t       = CamlinternalOO.t
-  type obj     = CamlinternalOO.obj    (**Internal representation of an object.*)
-  type closure = CamlinternalOO.closure(**Internal representation of a method.*)
-
-  val public_method_label : string -> tag
-  val new_method : table -> label
-  val new_variable : table -> string -> int
-  val new_methods_variables :
-    table -> string array -> string array -> label array
-  val get_variable : table -> string -> int
-  val get_variables : table -> string array -> int array
-  val get_method_label : table -> string -> label
-  val get_method_labels : table -> string array -> label array
-  val get_method : table -> label -> meth
-  val set_method : table -> label -> meth -> unit
-  val set_methods : table -> label array -> unit
-  val narrow : table -> string array -> string array -> string array -> unit
-  val widen : table -> unit
-  val add_initializer : table -> (obj -> unit) -> unit
-  val dummy_table : table
-  val create_table : string array -> table
-  val init_class : table -> unit
-  val inherits :
-    table -> string array -> string array -> string array ->
-    (t * (table -> obj -> Obj.t) * t * obj) -> bool -> Obj.t array
-  val make_class :
-    string array -> (table -> Obj.t -> t) ->
-    (t * (table -> Obj.t -> t) * (Obj.t -> t) * Obj.t)
-  type init_table = CamlinternalOO.init_table
-  val make_class_store :
-    string array -> (table -> t) -> init_table -> unit
-  val dummy_class :
-    string * int * int ->
-    (t * (table -> Obj.t -> t) * (Obj.t -> t) * Obj.t)
-
-  (** {6 Objects} *)
-
-  val copy : (< .. > as 'a) -> 'a
-  val create_object : table -> obj
-  val create_object_opt : obj -> table -> obj
-  val run_initializers : obj -> table -> unit
-  val run_initializers_opt : obj -> obj -> table -> obj
-  val create_object_and_run_initializers : obj -> table -> obj
-  external send : obj -> tag -> t = "%send"
-  external sendcache : obj -> tag -> t -> int -> t = "%sendcache"
-  external sendself : obj -> label -> t = "%sendself"
-  external get_public_method : obj -> tag -> closure
-    = "caml_get_public_method" "noalloc"
-
-  (** {6 Table cache} *)
-
-  type tables = CamlinternalOO.tables
-  val lookup_tables : tables -> closure array -> tables
-
-  (** {6 Builtins to reduce code size} *)
-
-  (*
-    val get_const : t -> closure
-    val get_var : int -> closure
-    val get_env : int -> int -> closure
-    val get_meth : label -> closure
-    val set_var : int -> closure
-    val app_const : (t -> t) -> t -> closure
-    val app_var : (t -> t) -> int -> closure
-    val app_env : (t -> t) -> int -> int -> closure
-    val app_meth : (t -> t) -> label -> closure
-    val app_const_const : (t -> t -> t) -> t -> t -> closure
-    val app_const_var : (t -> t -> t) -> t -> int -> closure
-    val app_const_env : (t -> t -> t) -> t -> int -> int -> closure
-    val app_const_meth : (t -> t -> t) -> t -> label -> closure
-    val app_var_const : (t -> t -> t) -> int -> t -> closure
-    val app_env_const : (t -> t -> t) -> int -> int -> t -> closure
-    val app_meth_const : (t -> t -> t) -> label -> t -> closure
-    val meth_app_const : label -> t -> closure
-    val meth_app_var : label -> int -> closure
-    val meth_app_env : label -> int -> int -> closure
-    val meth_app_meth : label -> label -> closure
-    val send_const : tag -> obj -> int -> closure
-    val send_var : tag -> int -> int -> closure
-    val send_env : tag -> int -> int -> int -> closure
-    val send_meth : tag -> label -> int -> closure
-  *)
-
-  type impl  = CamlinternalOO.impl =
-      GetConst
-    | GetVar
-    | GetEnv
-    | GetMeth
-    | SetVar
-    | AppConst
-    | AppVar
-    | AppEnv
-    | AppMeth
-    | AppConstConst
-    | AppConstVar
-    | AppConstEnv
-    | AppConstMeth
-    | AppVarConst
-    | AppEnvConst
-    | AppMethConst
-    | MethAppConst
-    | MethAppVar
-    | MethAppEnv
-    | MethAppMeth
-    | SendConst
-    | SendVar
-    | SendEnv
-    | SendMeth
-    | Closure of closure
-
-  (** {6 Parameters} *)
-
-  (** currently disabled *)
-  type params  = CamlinternalOO.params =
-    { mutable compact_table : bool;
-      mutable copy_parent : bool;
-      mutable clean_when_copying : bool;
-      mutable retry_count : int;
-      mutable bucket_small_size : int }
-
-  val params : params
-
-  (** {6 Statistics} *)
-
-  type stats  = CamlinternalOO.stats =
-    { classes : int;
-      methods : int;
-      inst_vars : int }
-  val stats : unit -> stats
-
-end
diff --git a/src/batteries.mllib b/src/batteries.mllib
index cd4df595..8c1c6e37 100644
--- a/src/batteries.mllib
+++ b/src/batteries.mllib
@@ -33,7 +33,6 @@ BatInnerPervasives
   BatMarshal
   BatNativeint
   BatNum
-  BatOo
   BatPervasives
   BatPrintexc
   BatPrintf
diff --git a/src/batteries.mlv b/src/batteries.mlv
index 81047a89..1a4e47e4 100644
--- a/src/batteries.mlv
+++ b/src/batteries.mlv
@@ -82,7 +82,6 @@ module Map = BatMap
 module Marshal = BatMarshal
 (* MoreLabels *)
 module Nativeint = BatNativeint
-module Oo = BatOo
 (* Parsing *)
 module Printexc = BatPrintexc
 module Printf = BatPrintf (* UNTESTED FOR BACKWARDS COMPATIBILITY *)

From 1a2ccff4ffde22138d4929e3fcbaacda124eb074 Mon Sep 17 00:00:00 2001
From: Cedric Cellier <rixed@happyleptic.org>
Date: Mon, 30 Sep 2019 05:17:56 +0200
Subject: [PATCH 08/11] Make BatSeq.Exceptionless.combine really exceptionless
 (#917)

Now, BatSeq.Exceptionless.combine returns the longest sequence possible
(stopping when one of the input sequence ends).

Closes #418
---
 src/batSeq.ml  | 16 ++++++++++++----
 src/batSeq.mli |  2 +-
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/src/batSeq.ml b/src/batSeq.ml
index 42842eb1..2687521d 100644
--- a/src/batSeq.ml
+++ b/src/batSeq.ml
@@ -429,6 +429,7 @@ end
 include Infix
 
 module Exceptionless = struct
+  (*$< Exceptionless *)
   (* This function could be used to eliminate a lot of duplicate code below...
      let exceptionless_arg f s e =
      try Some (f s)
@@ -477,11 +478,18 @@ module Exceptionless = struct
     try Some (min s)
     with Invalid_argument _ -> None
 
-  let combine s1 s2 =
-    try Some (combine s1 s2)
-    with Invalid_argument _ -> None
+  let rec combine s1 s2 () = match s1 (), s2 () with
+  | Nil, Nil ->
+    Nil
+  | Cons(e1, s1), Cons(e2, s2) ->
+    Cons((e1, e2), combine s1 s2)
+  | _ ->
+    Nil
 
   (*$T combine
-    equal (combine (of_list [1;2]) (of_list ["a";"b"])) (of_list [1,"a"; 2,"b"])
+    equal (combine (of_list [1;2]) (of_list ["a";"b"]))     (of_list [1,"a"; 2,"b"])
+    equal (combine (of_list [1;2]) (of_list ["a";"b";"c"])) (of_list [1,"a"; 2,"b"])
+    equal (combine (of_list [1;2;3]) (of_list ["a";"b"]))   (of_list [1,"a"; 2,"b"])
   *)
+  (*$>*)
 end
diff --git a/src/batSeq.mli b/src/batSeq.mli
index 93fc8e59..fca06637 100644
--- a/src/batSeq.mli
+++ b/src/batSeq.mli
@@ -322,5 +322,5 @@ module Exceptionless : sig
   val reduce : ('a -> 'a -> 'a) -> 'a t -> 'a option
   val max : 'a t -> 'a option
   val min : 'a t -> 'a option
-  val combine : 'a t -> 'b t -> ('a * 'b) t option
+  val combine : 'a t -> 'b t -> ('a * 'b) t
 end

From d563bd21dadea4145ba7e5943a58cb88d2c42601 Mon Sep 17 00:00:00 2001
From: Cedric Cellier <rixed@happyleptic.org>
Date: Mon, 30 Sep 2019 05:20:14 +0200
Subject: [PATCH 09/11] BatString.split_on_char and nsplit must never return an
 empty list (#918)

BatString.split_on_char behavior matches the one of
Legacy.String.split_on_char, and that nsplit behavior matches the one
of split_on_char.

Closes #845
Closes #846
---
 src/batString.mliv | 4 +++-
 src/batString.mlv  | 8 ++++----
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/batString.mliv b/src/batString.mliv
index c3367331..623abb84 100644
--- a/src/batString.mliv
+++ b/src/batString.mliv
@@ -745,6 +745,7 @@ val split_on_char: char -> string -> string list
       (String.split_on_char sep s) = s]).
     - No string in the result contains the [sep] character.
 
+    Note: prior to NEXT_RELEASE [split_on_char _ ""] used to return an empty list.
     @since 2.5.3
 *)
 
@@ -788,7 +789,8 @@ val rsplit : string -> by:string -> string * string
 val nsplit : string -> by:string -> string list
 (** [nsplit s sep] splits the string [s] into a list of strings
     which are separated by [sep] (excluded).
-    [nsplit "" _] returns the empty list.
+    [nsplit "" _] returns a single empty string.
+    Note: prior to NEXT_RELEASE [nsplit "" _] used to return an empty list.
 
     Example: [String.nsplit "abcabcabc" "bc" = ["a"; "a"; "a"; ""]]
 *)
diff --git a/src/batString.mlv b/src/batString.mlv
index 706b641c..3779d3a2 100644
--- a/src/batString.mlv
+++ b/src/batString.mlv
@@ -383,7 +383,7 @@ let rsplit str ~by:sep =
    of substrings from the end to the beginning, so as to avoid a call to [List.rev].
 *)
 let nsplit str ~by:sep =
-  if str = "" then []
+  if str = "" then [""]
   else if sep = "" then invalid_arg "String.nsplit: empty sep not allowed"
   else
     (* str is non empty *)
@@ -412,7 +412,7 @@ let nsplit str ~by:sep =
 
 (*$T nsplit
   nsplit "a;b;c" ~by:";" = ["a"; "b"; "c"]
-  nsplit "" ~by:"x" = []
+  nsplit "" ~by:"x" = [""]
   try nsplit "abc" ~by:"" = ["a"; "b"; "c"] with Invalid_argument _ -> true
   nsplit "a/b/c" ~by:"/" = ["a"; "b"; "c"]
   nsplit "/a/b/c//" ~by:"/" = [""; "a"; "b"; "c"; ""; ""]
@@ -420,7 +420,7 @@ let nsplit str ~by:sep =
 *)
 
 let split_on_char sep str =
-  if str = "" then []
+  if str = "" then [""]
   else
     (* str is non empty *)
     let rec loop acc ofs limit =
@@ -433,7 +433,7 @@ let split_on_char sep str =
 
 (*$T split_on_char
   split_on_char ';' "a;b;c" = ["a"; "b"; "c"]
-  split_on_char 'x' "" = []
+  split_on_char 'x' "" = [""]
   split_on_char '/' "a/b/c" = ["a"; "b"; "c"]
   split_on_char '/' "/a/b/c//" = [""; "a"; "b"; "c"; ""; ""]
 *)

From 43068b3d3eea4354f8bcef3d7a042e7138e15edc Mon Sep 17 00:00:00 2001
From: Cedric Cellier <rixed@happyleptic.org>
Date: Mon, 30 Sep 2019 05:50:21 +0200
Subject: [PATCH 10/11] Add Legacy.Result for OCaml >= 4.8.0 (#913)

Now, users can pattern match Result.t returned from some library using
Legacy.Result.Error while Batteries is opened.

Ref #839
---
 src/batteries.mlv | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/batteries.mlv b/src/batteries.mlv
index 1a4e47e4..37e80418 100644
--- a/src/batteries.mlv
+++ b/src/batteries.mlv
@@ -47,6 +47,7 @@ module Legacy = struct
   module Big_int = Big_int
   module Bigarray = Bigarray
   module Str = Str
+##V>=4.8## module Result = Result
 end
 
 (* stdlib modules *)

From 3c323ef1707b9f89c2d9c8694f0163853b21e61c Mon Sep 17 00:00:00 2001
From: Cedric Cellier <rixed@happyleptic.org>
Date: Tue, 1 Oct 2019 03:07:10 +0200
Subject: [PATCH 11/11] List.sum [] is now 0 (#916)

List.sum and List.fsum default to 0 (or 0.0) in case the list is empty.
Previously, this was raising Invalid_argument.

Closes #519
---
 src/batArray.mlv |  5 +++--
 src/batList.mliv |  6 ++++--
 src/batList.mlv  | 14 +++++++++-----
 3 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/src/batArray.mlv b/src/batArray.mlv
index 64efbcb5..c6fd13c9 100644
--- a/src/batArray.mlv
+++ b/src/batArray.mlv
@@ -592,12 +592,13 @@ let min_max a =
     try ignore (min_max [||]); false with Invalid_argument _ -> true
 *)
 
-let sum = reduce (+)
-let fsum = reduce (+.)
+let sum = fold_left (+) 0
+let fsum = fold_left (+.) 0.
 
 (*$T sum
   sum [|1;2;3|] = 6
   sum [|0|] = 0
+  sum [||] = 0
 *) (*$T fsum
      fsum [|1.0;2.0;3.0|] = 6.0
      fsum [|0.0|] = 0.0
diff --git a/src/batList.mliv b/src/batList.mliv
index b2aba6b8..560b4db6 100644
--- a/src/batList.mliv
+++ b/src/batList.mliv
@@ -298,12 +298,14 @@ val min : 'a list -> 'a
 
 val sum : int list -> int
 (** [sum l] returns the sum of the integers of [l].
-    @raise Invalid_argument on the empty list.
+    Returns [0] on the empty list.
+    Note: prior to NEXT_RELEASE, used to raise Invalid_argument on the empty list.
  *)
 
 val fsum : float list -> float
 (** [fsum l] returns the sum of the floats of [l].
-    @raise Invalid_argument on the empty list.
+    Returns [0.] on the empty list.
+    Note: prior to NEXT_RELEASE, used to raise Invalid_argument on the empty list.
  *)
 
 val favg : float list -> float
diff --git a/src/batList.mlv b/src/batList.mlv
index b60454c0..562dcdae 100644
--- a/src/batList.mlv
+++ b/src/batList.mlv
@@ -1369,11 +1369,15 @@ let reduce f = function
 
 let min l = reduce Pervasives.min l
 let max l = reduce Pervasives.max l
-let sum l = reduce (+) l
+let sum l = fold_left (+) 0 l
+(*$= sum & ~printer:string_of_int
+  2 (sum [1;1])
+  0 (sum [])
+*)
 
 let fsum l =
   match l with
-  | [] -> invalid_arg "List.fsum: Empty List"
+  | [] -> 0.
   | x::xs ->
     let acc = ref x in
     let rem = ref xs in
@@ -1386,9 +1390,9 @@ let fsum l =
         rem := xs
     done;
     !acc
-(*$T fsum
-  try let _ = fsum [] in false with Invalid_argument _ -> true
-  fsum [1.;2.;3.] = 6.
+(*$= fsum & ~printer:string_of_float
+  0. (fsum [])
+  6. (fsum [1.;2.;3.])
 *)
 
 let favg l =
