Line Filters in OCaml

Our line filter program reads input from stdin, processes it, and then prints a derived result to stdout. In this case, we’ll create a program that capitalizes all input text.

open Printf

(* Read lines from stdin and process them *)
let process_lines () =
  try
    while true do
      let line = input_line stdin in
      let uppercase_line = String.uppercase_ascii line in
      printf "%s\n" uppercase_line
    done
  with
  | End_of_file -> ()  (* End of input, exit normally *)
  | e -> 
      (* Handle other exceptions *)
      eprintf "Error: %s\n" (Printexc.to_string e);
      exit 1

(* Main function *)
let () = process_lines ()

Let’s break down the code:

  1. We use the open Printf statement to bring printf functions into scope.

  2. The process_lines function is the core of our program:

    • It uses a try-with block to handle exceptions.
    • Inside an infinite loop, it reads a line from stdin using input_line.
    • It then converts the line to uppercase using String.uppercase_ascii.
    • The uppercase line is printed to stdout using printf.
    • This continues until an End_of_file exception is raised (which happens when there’s no more input).
    • Any other exceptions are caught, printed to stderr, and cause the program to exit with an error code.
  3. The main part of the program simply calls process_lines.

To try out our line filter, first make a file with a few lowercase lines:

$ echo 'hello'   > /tmp/lines
$ echo 'filter' >> /tmp/lines

Then use the line filter to get uppercase lines:

$ cat /tmp/lines | ocaml line_filter.ml
HELLO
FILTER

This OCaml version provides the same functionality as the original example. It reads lines from standard input, converts them to uppercase, and prints the result to standard output. The main difference is in error handling: OCaml uses exceptions for end-of-file and other errors, while the original example used a specific error checking method.