An FP/Clojure Ah Hah! Moment

I have purchased either in e-book or printed form most of the major books on Clojure, including both from Manning Publications, Apress, O’Reilly and The Pragmatic Bookshelf . All these books are well written; all have slightly different approaches and styles.

Some are tutorial in nature, others are more like a tutorial/reference, and others contain philosophy in addition to tutorial. In some of these references, there is a sense you have programmed in Java previously, and I sense, and it is not directly implied, that the reader has dabbled in a Lisp dialect.

My Ah Hah! moment came recently when I realized that until a couple of years ago, the last languages I used in the commercial world were C++, Java 2, and Perl. Functional Programming (FP) was an academic subject, and though I had heard of Python, there was no pressing reason for me to learn it, at least back then. These books are written by authors with mostly a different programming learning and implementation environments.

So, as I work my way through Clojure In Action and Code Lesson’s Intro to Clojure, there are additional things for me to learn, the biggest of these the differing implementation environments and curriculum from when I started programming.

Here we go, then.


Manning’s Clojure in Action

Many of you may already have Amit Rathore’s Clojure in Action through Manning’s MEAP program, but good news for non-MEAP people, like me, Amazon has already indicated they are shipping me Clojure in Action soon. That means Code Lesson’s Clojure course should start soon.


More Clojure Training

As I await the release of Amit Rathore’s Clojure In Action and the subsequent on-line course on CodeLesson, I am out beating the bushes for more Clojure training, and I found labrepl.  I wound up installing lab_repl, and using cake repl to issue these startup commands:


(require 'labrepl)

(labrepl/-main)

Then, I went to localhost:8080 to use the labrepl web application.

There are instructions to install into Eclipse http://code.google.com/p/counterclockwise/.

This tutorial comes from Relevance, who teach Clojure.


Clojure Training / Clojure Koans

I am not the first person to start learning Clojure, who is looking for tutorial-level material, and I will not be the last. My programming experience goes back thirty years, but all of that time has been using so-called imperative programming languages like PL/I, C, C++, VB/VBA/VBScript, and yes, a little bit of Java. Learning those languages both formally in the classroom and from the more experienced people in our environments could not prepare us for functional programming.

I have been using the 4Clojure web site, but found some problems marked elementary or simple seemed the opposite. I have tended to treat it as a game rather than a learning experience. I had seen Clojure Koans mentioned in Clojure Google Groups and on blogs, but never investigated it … until today.

I recommend it.

 

 

 

 


How We Learned Programming

The first time I touched a computer was in college. As we were graduating high school, the prevailing wisdom said don’t bother learning anything about computers. Pretty soon, they will all be programming themselves. I guess pretty soon covered a longer time span than the expected normal time span for that phrase.

My first experience was on an IBM connected teletype directly connected from the Chemistry Department in Parsons Lab at UNH to the IBM 360 computer in the Math Department in Kingsbury Hall. It was awful. You had to type perfectly, or count the number of characters as you erased backwards. A few years from that day, I used punch cards for a Fortran IV course at Northeastern University, and to me they were considerably better than a teletype. Despite enduring all this, I was spared those punched programs on paper tape.

Finally, I realized I had to have a common day higher level programming language, discrete [data] structures, and a course in someone’s assembly language — I chose IBM 370 assembler — under my belt. That allowed me a passage into software technical writing about languages and operating systems.

Those courses lead to Harvard University Extension School for something called a CAS — they have a masters program now — which included the data structures, Pascal, discrete mathematics, and computability theory, along with fleshing out operating system theory and a wonderful course called the anatomy and physiology of a computer. Before I graduated, I had already been programming for two years using PL/I.

Now, the big push is functional programming, along with a group of computer programming languages that are not so relatively new, and some, like Scala and Clojure, that are relatively new. Given Computer Science degrees were not around when I went to college it is hard to say what the curriculum changes are, but looking at typical curriculum makes me think obvious things have changed, like no longer requiring assembly language, and the math requirements have migrated to include support for functional programming.

I never heard of Lambda calculus, but having looked at the structure of more modern computer programming languages, my guess is Lambda calculus is taught a lot, if not as a separate course, then embedded in other courses. I believe I have to learn it, and I’ve started by ordering an introduction to functional programming .


What is Clojure? Who Should Use It?

I am writing this post to try to dig into why someone wants to use Clojure; who would use it to implement production grade software; and who is qualified to use Clojure. I saw a post today concerning the compatibility between Clojure releases and between the Clojure “contrib” library. One answer indicated Clojure is not for the masses; is for hackers and people who like computer science; and for those who want to work with a fun language. I saw history repeating itself with this answer.

Gordon Bell’s law about functions (classes) in computers being replaced by cheaper hardware about every decade made me think about things being reinvented, especially arguments in computer technology, most notably computer programming languages. The argument I read about who should use Clojure was like Deja Vu all over again .

What is perhaps not understood, or I cannot detect the understanding in what I am reading, is that not all computer work is fun; you do not always get to choose your language; and you have to be innovative in your work with the tools you have or can grab.

If you go to Clojure’s home page and read the first few paragraphs and also click on Rationale, Rich Hickey, Clojure’s founder, seems to be saying that Clojure was designed with balance, pragmatism, and trade-offs. This does not seem to be directed at an elite group of people.

I understand why people like Clojure and other Lisp dialects. Coming from PL/I and C and considering the other languages available in the 1980s, DEC’s  Bliss-32 was like a dream. I realize most readers today might find Bliss dreadful, but it allowed me to express hardware architecture functions in a clearer way than assembly language or C ever could (C++ did not exist for commercial use in 1987.) Even PL/I has a construct that supports multiple function entry points, aka multiple function interfaces. It sounds a little like polymorphism to me.

Now back to the response to the compatibility between Clojure’s released versions: the answer itself did not bother me. History repeating itself without looking to arguments in the past seemed futile. Maybe that’s what we do every 10 or 20 years, start discussions, thinking they are new, not realizing we are restarting arguments from the past.

If Clojure winds up becoming a salon-class, elite language that will be a shame. There are aspects to Lisp dialects and Clojure specifically that I believe should become part of mainstream. I find Lisp syntax far easier to read than, say, Haskell’s.

So, my thoughts about Clojure and who should use it, if not already obvious, are use it, if it makes sense in your environment. Learn Clojure well and what drives it, specifically functional programming and environments requiring synchronization. If you can’t use it, learning will probably help you with your current language.


Clojure Exercise Well

I found some nice Clojure exercises http://www.cis.upenn.edu/~matuszek/cis554-2010/Assignments/clojure-01-exercises.html .

Basically, practice makes perfect, especially with recursion. Oh yes, I learned recursion taking a course in data structures long ago, and re-learned recursion when learning C. I have never used recursion in production that I can remember. That is not true with Lisp dialects.

There are other ways to remove list duplicates, but I wanted to roll my own on this one. I made two mistakes. One was not having an else for the second if expression. The other was checking for null of new-seq instead of (first new-seq).


(ns repl-test
  (:gen-class)
  (:use clojure.contrib.command-line)
  (:require [clojure.contrib.string :as cstr])
  (:require [clojure.contrib.trace :as ctr])
  (:use clojure-csv.core))

(def d3 [1 2 3 1 4 1 2])

(defn x-in-seq [x temp-seq]
  (if (nil? (some #(= x %) temp-seq))
   x))

(defn f1
  [in-seq]
  (loop [new-seq [] cur-seq in-seq]
    (if (nil? (first cur-seq))
      new-seq
      ;(if-not (nil? (ctr/trace (x-in-seq (first cur-seq) new-seq)))
      (if-not (nil? (x-in-seq (first cur-seq) new-seq))
         (recur (conj new-seq (first cur-seq)) (rest cur-seq))
         (recur new-seq (rest cur-seq))))))

(defn -main
[& args]

(println (f1 d3)))

Is Learning Functional Programming a Good Thing?

Those folks who follow this blog or http://octopusgrabbus.wordpress.com might come to the conclusion that I’ve abandoned Python, but that is not the case. I started learning Python in 2009 by writing some applets to perform database housekeeping, and then eventually implemented an application in 2010 for our water department. This application, which includes a Django-powered web site was written almost exclusively in Python.

I have been interested in functional programming for a few years now, and started looking at Haskell a couple of years ago. As the deadline to start designing our water department application loomed closer,  I did not know Haskell well enough to use it. Also, as a language, Haskell did not appear to have the broad library support enjoyed by Python. So, I chose Python as the implementation language for this project.

Earlier this year I came across a description of The Joy of Clojure at my favorite book sellers — http://softpro.com — and started learning more about Clojure. Having never programmed in a functional programming language or a Lisp dialect, I am finding Clojure a little daunting. However, a project has presented itself, which involves a faster way of processing our billing data through address verification.

A project is like a carrot and stick; that is it provides cause to use extraordinary effort to learn something new quickly or solve a particularly difficult problem. The project will require more than a Clojure program. Some 4GL and bash scripts will be used. However, the Clojure program will be substantial enough to get me familiar with the language and will have required enough effort to start writing code.

One of the things that has attracted me to functional programming (FP) languages is the same thing that attracted me to object oriented languages when I first learned C++ in the 1990s. Learning C++ improved my overall programming skills, whether I was writing object-oriented software or not. With learning C++, my analogy was it was like rotating your mind 90 degrees. With Clojure it is that and more.

Just one of the ways that learning Clojure has made me think differently is using the various sequence functions. Most of what I want to do with billing data fits well into Clojure’s strengths. That is you can apply the same functions to all the data and sort out data easily that does not fit your needs. At the moment, I do not see a use for using Clojure in a multi-process/multi-threaded environment.

I am also appreciating providing for data at the beginning, binding in Clojure, declaring variables in imperative languages like C. Python’s strength in the the ability to declare an object anywhere is also in my opinion a weakness that can lead to sloppy style, and I know this from direct experience.

So my conclusion is this. If I never write another line of Clojure code after my current project, my time will not have been wasted. Clojure requires a different way of thinking. It never hurts to take a different point of view, especially with problem solving. However, I think more Clojure projects will be forthcoming.


In Clojure, It’s All (a lot of it at least) About Reduction

This blog http://blogs.foognostic.net/2009/06/reduce-your-way-into-good-clojure/ and The Joy of Clojure http://joyofclojure.com/ are among many who talk about reduction being a major component in Clojure. They are right. Reduction is big stuff, especially coming from the imperative programming world.

I wrote this function:

(def accumail-url-keys ["CA", "STREET", "STREET2", "CITY", "STATE",
"ZIP", "YR", "BILL_NO", BILL_TYPE"])

(defn ret-params
    "Generates all q-parameters and returns them in a vector of
vectors."
    [all-csv-rows]
    (let [param-vec [[]] ]
        (doseq [one-full-csv-row all-csv-rows]
            (let [accumail-csv-row one-full-csv-row
                  q-param (zipmap accumail-url-keys accumail-csv-row)
                  accu-q-param (first (rest (split-at 3 q-param)))
                  billing-param (first (split-at 3 q-param))]
                (conj param-vec accu-q-param billing-param)))
         param-vec))

The goal of this function was to take parsed csv file rows from clojure-csv’s parse-csv function, and create a sequence of html tags and values that would be returned and used as :query-param values in multiple clj-http’s client/get calls.

But this function did not work, because param-vec is unmutable, having been initialized to an empty vector of vectors. I have made progress learning Clojure, but it has only been a few weeks programming in a functional programming language as opposed to years of empirical programming.

Fortunately for me and many others, there is the Clojure Google Group, and someone came up with using reduce. That did the trick. So, to make the transition from empirical to functional programming reduce is a gateway to dealing with sequences.

Now the function looks like this:

(defn ret-params
    "Generates all q-parameters and returns them in a vector of vectors."
    [all-csv-rows]
    (reduce
      (fn [param-vec one-full-csv-row]
        (let [q-param (zipmap accumail-url-keys one-full-csv-row)
              accu-q-param (first (rest (split-at 3 q-param)))
              billing-param (first (split-at 3 q-param))]
          (conj param-vec [accu-q-param billing-param])))
      []
      all-csv-rows))

and each arranged vector can then be put into map format for :query-params like so
(look for into further down in main):


(defn -main [& args]
  (with-command-line args
    "Get csv file name"
    [[file-name ".csv file name" "resultset.csv"]]
    [[file-name ".csv file name" 1]]
    (println "file-name:", file-name)
    (let [parsed-csv-output (gen-parsed-csv-file file-name)
          parsed-csv-vectors (ret-params parsed-csv-output)]
          (doseq [one-parsed-csv-vector parsed-csv-vectors]
            (println (into {} (first one-parsed-csv-vector)))))))

Of course, the println will be replaced with more function calls that take this data and write out another csv file suitable for a database upload.


Creating :query-params For clj-http get

Most of the U.S. mail our town sends out is barcoded. Before we can barcode an address, it must be verified by software recognized by the U.S. Post Office. This software, AccuMail (SmartSoftUsa) runs on Windows workstation or server. We have an ActiveX toolkit to accompany the base software. This means a Microsoft IIS web server running an ASP page can talk to the AccuMail address verification software using ActiveX. Such an ASP page has been working for years, and processes our addresses serially.

Given the tags expected by the ASP page, these are a def in the Clojure program:

(def accumail-url-keys ["CA", "STREET", "STREET2", "CITY", "STATE", "ZIP"] )

These tags merged with part of the input data forms a :query-params map used in a clj-http get call like this:

(client/get "http://site.com/search" {:query-params {"q" "foo, bar"}})

I needed a way to create a :query-params map for my data. Here is what I have so far. The :query-params just print out for now, but eventually they will be used in a clj-http get call to the AccuMail server.

Here is the input data from our receivables database:

1,266 BROADWAY APT 1,,NULLINGHAM,ZA,02474,11,900034,e
1,66 PLEASANT ST #2,,NULLINGHAM,ZA,02476,11,900035,e
1,254 FLORENCE AVE,,NULLINGHAM,ZA,02476,11,900036,e
1,75 ZARATHON ST,,NULLINGHAM,ZA,02474,11,900037,e
1,5 VIKING COURT,47,NULLINGHAM,ZA,02474,11,31879,e
1,94 FAIRMONT ST, ,NULLINGHAM,ZA,02474,11,31880,e
1,12 OLDHAM RD, ,NULLINGHAM,ZA,02474,11,31881,e
1,11 NEWPORT STREET,APT 1,NULLINGHAM,ZA,02476,11,31882,e
1,14A GROVE ST, ,NULLINGHAM,ZA,02476,11,31883,e
1,1 KENILWORTH RD, ,NULLINGHAM,ZA,02476,11,31884,e

Here’s the program:

(ns test-csv
  (:gen-class)
  (:use clojure.contrib.command-line)
  (:use clojure-csv.core))

(def accumail-url-keys ["CA", "STREET", "STREET2", "CITY", "STATE", "ZIP"] )

(defn gen-parsed-csv-file
    "Returns a sequence generated by parse-csv"
    [file-name]
    (let [data (slurp file-name)
     all-csv-rows (parse-csv data)]
      (lazy-seq (drop-last 1 all-csv-rows))))

(defn gen-qparams
    "Generates all q-parameters from accumail-url-keys and a lazy sequence returned from parse-csv"
    [all-csv-rows]
    (doseq [one-full-csv-row all-csv-rows]
        (let [accumail-csv-row (first (split-at 6 one-full-csv-row))
              q-param (zipmap accumail-url-keys accumail-csv-row)]
        (println q-param))))

(defn -main [& args]
  (with-command-line args
    "Get csv file name"
    [[file-name ".csv file name" "resultset.csv"]]
    [[file-name ".csv file name" 1]]
    (println "file-name:", file-name)
    (gen-qparams (gen-parsed-csv-file file-name))))

And, here is the output. To reiterate, eventually, this :query-params data will be passed to a client-get call.

file-name: resultset.csv
{ZIP 02474, STATE ZA, CITY NULLINGHAM, STREET2 , STREET 266 BROADWAY APT 1, CA 1}
{ZIP 02476, STATE ZA, CITY NULLINGHAM, STREET2 , STREET 66 PLEASANT ST #2, CA 1}
{ZIP 02476, STATE ZA, CITY NULLINGHAM, STREET2 , STREET 254 FLORENCE AVE, CA 1}
{ZIP 02474, STATE ZA, CITY NULLINGHAM, STREET2 , STREET 75 ZARATHON ST, CA 1}
{ZIP 02474, STATE ZA, CITY NULLINGHAM, STREET2 47, STREET 5 VIKING COURT, CA 1}
{ZIP 02474, STATE ZA, CITY NULLINGHAM, STREET2  , STREET 94 FAIRMONT ST, CA 1}
{ZIP 02474, STATE ZA, CITY NULLINGHAM, STREET2  , STREET 12 OLDHAM RD, CA 1}
{ZIP 02476, STATE ZA, CITY NULLINGHAM, STREET2 APT 1, STREET 11 NEWPORT STREET, CA 1}
{ZIP 02476, STATE ZA, CITY NULLINGHAM, STREET2  , STREET 14A GROVE ST, CA 1}
{ZIP 02476, STATE ZA, CITY NULLINGHAM, STREET2  , STREET 1 KENILWORTH RD, CA 1}

Edit: 7/21/2011 16:03
———————-

Here is a cleaned up version of gen-qparams

(defn gen-parsed-csv-file
"Returns a sequence generated by parse-csv"
[file-name]
(let [  data (slurp file-name)
all-csv-rows        (parse-csv data)
clean-csv-rows      (if (= 0 (count (first (last all-csv-rows))))
(drop-last 1 all-csv-rows)
all-csv-rows)]

clean-csv-rows))