Line Filters in Clojure

A line filter is a common type of program that reads input on stdin, processes it, and then prints some derived result to stdout. grep and sed are common line filters.

Here’s an example line filter in Clojure that writes a capitalized version of all input text. You can use this pattern to write your own Clojure line filters.

(ns line-filters.core
  (:require [clojure.string :as str])
  (:gen-class))

(defn -main [& args]
  (doseq [line (line-seq (java.io.BufferedReader. *in*))]
    (println (str/upper-case line)))
  (flush))

Let’s break down this code:

  1. We define a namespace and require the clojure.string library for string manipulation.

  2. The -main function is the entry point of our program.

  3. We use line-seq with java.io.BufferedReader. to create a lazy sequence of lines from standard input.

  4. We iterate over each line using doseq.

  5. For each line, we use str/upper-case to convert it to uppercase and println to print it.

  6. Finally, we flush the output to ensure all data is written.

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 | lein run
HELLO
FILTER

Note: To run this Clojure script, you need to have Leiningen installed and set up a project. Alternatively, you can use clj with the appropriate classpath set up.

This Clojure version accomplishes the same task as the original example, reading lines from standard input, converting them to uppercase, and printing the result. The main differences are:

  1. Clojure uses line-seq instead of a scanner to read lines.
  2. String manipulation is done using the clojure.string library.
  3. Error handling is implicit; Clojure will throw exceptions if there are I/O errors.

Remember to handle potential exceptions in a production environment.