ocaml-batteries-team / batteries-included

Batteries Included project
http://ocaml-batteries-team.github.com/batteries-included/hdoc2/
Other
516 stars 106 forks source link

Give example usage for BatEnum.clump #882

Open blaiseli opened 5 years ago

blaiseli commented 5 years ago

I fail to understand how to use BatEnum.clump and whether it is actually what I need (I want to process an enum four elements by four elements). It would be nice to have more examples in the documentation.

gasche commented 5 years ago

clump can be used for this but the API will not be very convenient: it will call a ('a -> unit) function on each of the four elements in turn, so unless your processing is a rather simple accumulation/aggregation it can be painful to use.

I would use either group or the combination of take (get the four elements, as an enum) and drop (drop the first four elements, and work on the rest). The nicest tool for your needs would be split_at : int -> 'a t -> 'a t * 'a t, which returns an enumeration of the first N elements and an enumeration of the rest, but unfortunately it is available in List and LazyList but not Enum or Seq (which I would prefer over Enum for most needs, as it is simpler to use and reason about, and faster).

gasche commented 5 years ago

(Your suggestion of including examples is excellent and not yet resolved.)

blaiseli commented 5 years ago

Thanks for your suggestions. I ended up doing things by using BatEnum.from on a function that does four BatEnum.get.

It works, but ways to improve speed would be welcome. So I looked at Seq, but I'm not sure I can go that way because of this:

Since enumerations are consumable and sequence are not, it is not possible to have the inverse operations, i.e. of_enum

The Enum I'm working with comes from BatIO.lines_of BatIO.stdin. Is there a better way of processing stdin line by line ?

UnixJunkie commented 5 years ago

Maybe:

let lines_of_file (fn: filename): string list =
  with_in_file fn (fun input ->
      let res, exn = BatList.unfold_exc (fun () -> input_line input) in
      if exn <> End_of_file then
        raise exn
      else res
    )

or

(* call f on lines of file *)
let iter_on_lines_of_file fn f =
  let input = open_in_bin fn in
  try
    while true do
      f (input_line input)
    done
  with End_of_file -> close_in input

or

(* map f on lines of file *)
let map_on_lines_of_file (fn: filename) (f: string -> 'a): 'a list =
  with_in_file fn (fun input ->
      let res, exn = L.unfold_exc (fun () -> f (input_line input)) in
      if exn = End_of_file then res
      else raise exn
    )