December 22, 2020

Learning Clojure - Implementing echo

As I wrote previously, I am learning the Clojure programming language as one of my personal Learning Projects.

Previously, I presented my implementations of true and false, the classic Unix command-line utilities. Next on the list is echo, a useful utility for writing information out to the screen. Well, technically it writes to the standard output, but the default is that that is the screen, so it works out the same in the end.

Now, let's take a look at the code:

(ns echo.core

(require '[clojure.string :as str])

(defn -main [& args]
  (if (= (count args) 0)
    (if (= (first args) "-n") (print (str/join " " (rest args))) (println (str/join " " args)))))

As before, I'll only explain aspects of the code that are new.

The first new thing is the require statement. This makes the functions in the Clojure string library available to the program and with the :as keyword, it is possible to more easily refer to them using the prefix str/.

In the definition of the -main function, the [& args] indicates that the function takes a list of arguments and the & indicates that args is an optional value.

When no command-line arguments are passed in, the count of the arguments is zero. This is the first thing we check in the if expression, so we know that when we have zero arguments that not only do we not have anything to print, but that we also cannot possibly have the -n flag, so just print a newline and call it done.

Knowing that when we do have more than zero arguments, we must test for the presence of the -n flag. The convention for this flag is that it must be the first argument present on the command-line. The arguments are in a list, so we check whether the head of the argument list, using first, equals -n. If we have a -n flag, we print the tail, using rest, and do not output a newline, with print. If the head of the list was not -n, then we output the entire argument list and also a newline character with println.

The join function (written str/join) that we now have access to because of the preceding require expression allows us to join strings together with our choice of join substring. This is a great help as I have lost count of the number of quick scraps of code I've written over the years to do this exact function and have made almost every mistake possible, especially ending up with unwanted trailing spaces at the end of the constructed string.

In terms of the layout of the code, I have tried to make it look idiomatic. Each programming language and programming langugage community develops its own distinctive style over time and this is considered its idiom. Lisp-based languages are still very new for me to be working with, so this is my best, educated, guess as to what it should look like. Hopefully, I'll learn more of the idioms of Clojure as I go and will come back and correct this later.

Tags: Clojure