user7732640
user7732640

Reputation:

Read a file line per line and store every line read in a single list

I'm a student and I've been given a exercice i've been struggling with for about a month or so. I'm trying to write a function in Ocaml. This function must read a text file which has a word per line, and it must store all the words in a list. But the problem is that this program must be a recursive one (which means no loops, no "while").

All I've been able to do so far is to create a function which reads the text file (pretty much like the BASH command "cat")

let dico filename =
  let f = open_in filename in
  let rec dico_rec () =
    try
      print_string (input_line f);
      print_newline ();
      dico_rec();
    with End_of_file -> close_in f
  in dico_rec() ;;

I just don't know how to do it. Ocaml is hardly my favourite language.

Upvotes: 0

Views: 2011

Answers (2)

Mitchell Gouzenko
Mitchell Gouzenko

Reputation: 129

open Printf

let file = "example.dat"

let () =
     let ic = open_in file in
     let rec build_list infile =
          try
               let line = input_line infile in
               line :: build_list(infile)
          with End_of_file ->
               close_in infile;
               [] in
     let rec print_list = function
          [] -> ()
          | e::l -> print_string e ; print_string " " ; print_list l in
     print_list(build_list(ic))

Edit: The algorithm I previously proposed was unnecessarily complicated. Try to understand this one instead.

To understand this recursion, we assume that build_list works correctly. That is, assume build_list correctly takes an open file as an argument and returns a list of lines in the file.

Now, let's look at the function's body. It reads a line from the file and calls build_list again. If there are N lines in the file, calling build_list again should return a list of the remaining N-1 lines in the file (since we just read the first line ourselves). We append the line we just read to the list returned from build_list, and return the resulting list, which has all N lines.

The recursion continues until it hits the base case. The base case is when there's an End_of_file. In this case we return an empty list.

Upvotes: 0

Jeffrey Scofield
Jeffrey Scofield

Reputation: 66803

Here's an alternate definition of build_list that is tail recursive. You can use it instead of @MitchellGouzenko's definition if your inputs can have many lines.

let rec build_list l =
    match input_line ic with
    | line -> build_list (line :: l)
    | exception End_of_file -> close_in ic; List.rev l

Upvotes: 3

Related Questions