2007/10/2, Olivier Andrieu <oandrieu@gmail.com>:
On 10/2/07, kirillkh <kirillkh@gmail.com> wrote:
> OK, so I'll give up the parsing/buffering part and only leave efficient
> exception handling. This should leave the user free to do anything with it,
> but prevent performance pitfalls. The following is based on Mattias
> Engdegard's code:
>
> (* I couldn't figure out, how to declare a polymorphic exception properly *)
> exception Done of 'a
>
> let fold_file (file: in_channel)
> (read_func: in_channel->'a)
> (elem_func: 'a->'b->'b)
> (seed: 'b) =
> let rec loop prev_val =
> let input =
> try read_func file
> with End_of_file -> raise (Done prev_val)
> in
> let combined_val = elem_func input prev_val in
> loop combined_val
> in
> try loop seed with Done x -> x
>
> And the usage for line counting:
>
> let line_count filename =
> let f = open_in filename in
> let counter _ count = count + 1 in
> fold_file f readline counter 0
>
> Since it's library code, we can tolerate the little annoyance of the second
> try-catch. As far as I can tell, this code has the same performance
> characteristics as yours: no consing + tail recursion. Any other problems
> with it?
well apart from the fact that you cannot have "polymorphic exceptions"
in OCaml, this kind of code is IMHO much more natural with an
imperative loop instead of a functional one:
let fold_file read chan f init =
let acc = ref init in
begin
try while true do
let d = read chan in
acc := f d !acc
done
with End_of_file -> ()
end ;
!acc
--
Olivier
A little weird to see such inherently functional construct as fold
implemented imperatively. But it's fine with me, as long as it does the
job. I wonder, though, how would the performance of a line counter
based on your code compare with the one suggested by Brian.