Version française
Home     About     Download     Resources     Contact us    
Browse thread
[Caml-list] Why do input* and readdir throw End_of_file ... annoying!
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Brian Hurt <brian.hurt@q...>
Subject: Re: [Caml-list] Why do input* and readdir throw End_of_file ... annoying!
On Fri, 6 Jun 2003, Richard Jones wrote:

> On Fri, Jun 06, 2003 at 01:49:55PM -0500, Brian Hurt wrote:
> > The problem with try/with is that it's way to easy to break tail recursion 
> > using try/with.  About every other week someone comes to the Ocaml 
> > beginners list where they are doing something like:
> 
> What's a good way to read all the lines of a file into a list? I
> can put it into the OCaml tutorial I'm writing.

The way I'd recommend doing it:

let read_all_lines chan =
    let rec loop accum =
        let line, eof = try (input_line chan), true
                        with End_of_file -> "", false
        in
        if eof then
            accum
        else
            loop (line :: accum)
    in
    List.rev (loop [])

The original poster's idea of a function:
   let my_input_line chan = 
      try Some(input_line chan)
      with End_of_file -> None

has the advantage of enlisting the type checker to make sure you handle 
the eof condition correctly everywhere.

For those seeking best performance, using the ExtLib would allow you to do 
the following:

let read_all_lines chan
    let e = Enum.from (fun () -> try input_line chan
                                 with End_of_file -> 
                                     raise No_more_elements)
    in
    ExtList.of_enum e

This has the effect of eliminating the List.rev.  Although at this point 
you should be very tempted to just keep it an enum, which are in some ways 
easier to work with than lists, and you don't read the data until you need 
it.  For example, to read in all the lines of one file, make them upper 
case, and write them out to another file, you might write:

let cap_all_lines inchan outchan
    let e = Enum.from (fun () -> try input_line inchan
                                 with End_of_file -> 
                                     raise No_more_elements)
    in
    let e' = Enum.map String.capitalize e
    in
    Enum.iter (fun x -> output_string outchan x; output_char '\n') e'

The advatange of this method is that only one line at a time needs to be 
in memory.

Brian


-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners