Category Archives: Clojure

So an F# Sequence Should Stick Around For a While

If you create a sequence in Clojure, the sequence sticks around within the scope of its creation. That is, once a Clojure sequence is created and bound to a var, nothing special has to be done to make sure its contents stick around. This is not so with F#.

Take this program


open System
open System.Collections.Generic
open System.Text
open System.IO
#nowarn "40"

let rec readLines () =
    seq {
    let line = Console.ReadLine()
    if not (line.Equals("")) then
           yield Int32.Parse(line)
           yield! readLines ()
    }

[<EntryPoint>]
let main argv =
    let inSeq = readLines ()    

    inSeq

    |> Seq.length

    |> printfn "%d lines read"

    // This will keep it alive enough to read your output
    Console.ReadKey() |> ignore
    0

Because of a sequences’ inherent laziness, the reading in of numbers does not begin until inSeq’s length is computed. Without caching inSeq, you will have to read the integers in again if you want to iterate the sequence, unless this change is made


let inSeq = readLines () |> Seq.cache

Advertisements

Leave a comment

Filed under Clojure, F#

Using A ref As A Mutable Global Flag

I have written a new, small Clojure program to compare this month’s and last month’s insurance report. This is similar to a project I did a year ago, except it involves one report our personnel department gets once a month, not two different reports. 

The program involves using Clojure’s jdbc interface, and is very much a typical database report that could have been written in Perl, or if the database had been Informix, in Informix 4GL. There’s nothing special about the program, except the code base was already in Clojure, and I wanted to keep the code base the same.

The only roadblock I ran into was setting status from the result of certain difference tests between last and this month, like whether a record wasn’t there this month, last month, whether or not the insurance product or premium had changed, or if someone had gone from an active to a retired status.

I tried figuring out a way to have a let binding contain return status from these different tests, so that these status values could be written into the report. After a while, I settled on a ref and dosync to set one global flag, so that later on in the program, had their been no errors, an appropriate message could be written to the file.

I don’t know whether I crossed into the mutable dark force, but, for one, I’m not convinced that carefully used mutable variables are a bad thing, especially, if you’ve designed the rest of your program not to take these shortcuts, because of coding laziness. Can you tell I’ve absorbed guilt from Clojure’s being immutable?

Leave a comment

Filed under Clojure

Does Clojure Tend To Encourage Small, Efficient Functions?

I have only two small Clojure projects, and other than writing tools on which nothing major depends, these projects will probably be the only ones in my current position. The rest will be done in Web languages and Perl. So, I enjoy a chance to enhance the Clojure projects.

I do not know why, and am not aware of any conscious prejudice, but writing Clojure code encourages me to create small functions, and external Clojure projects, like a utility project containing various odds and ends to handle sequences, time/date manipulation, and other useful stuff.

I have written enough Perl and Python code to appreciate what those languages do, but, for some reason, my functions tend to be longer and wider in definition than my Clojure functions.

4 Comments

Filed under Clojure

Finding A Less Risky Way To Use Clojure

My position represents either a sub-department or department of one. There is only one person in our municipality doing my kind of work, and a very knowledgeable consultant works with me. As my retirement looms in the next few years, I do not want to be known as someone who left a tangled mess. After all, more than a decade ago, I inherited just that because of the untimely passing of my predecessor, another one-person band. The mess was undocumented, uncommented Informix 4GL source code, virtually no build, no source code control, and no systems documentation.

The consultant with whom I work wants to standardize on the implementation language we use, and I agree with him. We haven’t chosen Perl because we think it is the best, but because a lot of people know it, and it works well for standalone and web applications. In our opinion, it doesn’t beat PHP for the web, but in a dual role works well for CGI and command-line, unattended applications.

After learning Clojure, I would rather write in it, even after having invested a store/forward configuration/meter reads system in Python. But, there is that trying to standardize thing I mentioned previously. So, I am going to take the advice I saw on one of the bulletin boards to someone just starting out. Write something and show it.

What I write will be tools on which someone coming into my job won’t have to maintain or reproduce, at least at the start. The rest of it, including a MySQL database crawler to keep the number of daily reads manageable at 14M rows of data, will be done in Perl. All of the people who said Clojure would affect my thinking even if I only learned it and never used it much were not kidding. My problem with Clojure is having to use something else. I guess that is a good thing for Clojure.

 

Leave a comment

Filed under Clojure

A Simple Clojure Program To Read an Informix Database

This post assumes you have Informix properly installed and have access to database tools like dbaccess. My configuration is running on CentOS 6.5 32-bit. It also assumes you can get the Informix JDBC driver installed into maven.

From the day I got my hands on The Joy of Clojure and eventually other excellent Clojure books, I have wanted to use Clojure to access an Informix database. In our case, it is an Informix SE database running on Linux.

This is what I did to get it running, with help from these stackoverflow questions and IBM Support. Although my first stackoverflow question involved korma, it made sense to keep things simple, and just use the Informix JDBC driver directly.

1) For SE, the latest support jdbc driver is 3.50.JC9, so that is what I installed.

2) You need to create a database. I created the stores7 directory and stores7.dbs. The demos I used all require that a database exist or be created.

3) Simple Java file installed at /opt/IBM/Informix_JDBC_Driver/demo/basic/SimpleSelect.java that we modified in a local directory, rebuilt, and ran


/**************************************************************************
*
* Licensed Materials - Property of IBM Corporation
*
* Restricted Materials of IBM Corporation
*
* IBM Informix JDBC Driver
* (c) Copyright IBM Corporation 1998, 2004 All rights reserved.
*
****************************************************************************/
/***************************************************************************
* Title: SimpleSelect.java
*
* Description: Demo a simple select operation
*
* An example of running the program:
*
* java SimpleSelect
* 'jdbc:informix-sqli://myhost:1533:informixserver=myserver;user=;password='
*
* Expected result:
*
* >>>Simple Select Statement test.
* URL = "jdbc:informix-sqli://myhost:1533/testDB:informixserver=myserver;user=;password="
* Select: column a = 11
* >>>End of Simple Select Statement test.
*
***************************************************************************
*/

import java.sql.*;
import java.util.*;

public class SimpleSelect {

public static void main(String[] args)
{
     String newUrl = "";

     newUrl = "jdbc:informix-sqli://steamboy:1498/testdb:informixserver=steamboy;usev5server=1;DBPATH=/home/cnorton/stores7";

     Connection conn = null;
     int rc;
     String cmd=null;
     Statement stmt = null;

     String testName = "Simple Select Statement";

     System.out.println(">>>" + testName + " test.");
     System.out.println("URL = "" + newUrl + """);

     try
     {
          Class.forName("com.informix.jdbc.IfxDriver");
     }
     catch (Exception e)
     {
          System.out.println("FAILED: failed to load Informix JDBC driver.");
     }

     try
     {
          conn = DriverManager.getConnection(newUrl);
     }
     catch (SQLException e)
     {
          System.out.println("FAILED: failed to connect!");
     }

     // Drop table before starting - ignore errors
     try
     {
          Statement dstmt = conn.createStatement();
          dstmt.executeUpdate("drop table x");
     }
     catch (SQLException e)
     { ; }
     try
     {
          stmt = conn.createStatement();
          cmd = "create table x (a smallint);";
          rc = stmt.executeUpdate(cmd);
     }
     catch (SQLException e)
     {
          System.out.println("FAILED: execution failed - statement: " + cmd);
          System.out.println("FAILED: " + e.getMessage());
     }

     try
     {
          cmd = "insert into x values (11);";
          rc = stmt.executeUpdate(cmd);
     }
     catch (SQLException e)
     {
          System.out.println("FAILED: execution failed - statement: " + cmd);
          System.out.println("FAILED: " + e.getMessage());
     }

     try
     {
          cmd = "insert into x values (22);";
          rc = stmt.executeUpdate(cmd);
     }
     catch (SQLException e)
     {
          System.out.println("FAILED: execution failed - statement: " + cmd);
          System.out.println("FAILED: " + e.getMessage());
     }

     // INFORMIX_EXTEXT_BEGIN Simple1.jav
     try
     {
          PreparedStatement pstmt = conn.prepareStatement("Select * from x "+ "where a = ?;");
          pstmt.setInt(1, 11);
          ResultSet r = pstmt.executeQuery();

          while(r.next())
          {
                 short i = r.getShort(1);

                 // verify result
                 if (i != 11)
                        System.out.println("FAILED: Expected = 11 Returned = " + i);
                 else
                        System.out.println("Select: column a = " + i);
          }
          r.close();
          pstmt.close();
     }
     catch (SQLException e)
     {
         System.out.println("FAILED: Fetch statement failed: " + e.getMessage());
     }
     // INFORMIX_EXTEXT_END Simple1.jav

     try
     {
          cmd = "drop table x";
          rc = stmt.executeUpdate(cmd);
          stmt.close();
     }
     catch (SQLException e)
     {
          System.out.println("FAILED: execution failed - statement: " + cmd);
          System.out.println("FAILED: " + e.getMessage());
     }

     try
     {
          conn.close();
     }
     catch (SQLException e)
     {
          System.out.println("FAILED: failed to close the connection!");
     }

     System.out.println(">>>End of " + testName + " test.");
   }
}

Here is the Clojure project.clj


(defproject db-test "0.1.0-SNAPSHOT"
     :description "Clojure database test"
     :url "http://example.com/FIXME"
     :license {:name "Eclipse Public License"
     :url "http://www.eclipse.org/legal/epl-v10.html"}
     :dependencies [[org.clojure/clojure "1.5.1"]
                    [org.clojure/tools.cli "0.1.0"]
                    [com.informix.jdbc/com.springsource.com.informix.jdbc "3.0.0.JC3"]
                    [org.clojure/java.jdbc "0.3.3"]]
     :repositories [["springsource-release" "http://repository.springsource.com/maven/bundles/release"]
                    ["springsource-external" "http://repository.springsource.com/maven/bundles/external"]]
     :main db-test.core
     :aot [db-test.core])

And here is the Clojure core.clj. test file.


(ns db-test.core
    (require [clojure.string :as str])
    (require [clojure.java.jdbc :as j])
    (:use [clojure.tools.cli])
    (:import java.util.Date)
    (:gen-class))

; Parses for options passed in on the command line.

(def if_SE_engine_type "SE")
(def if_SE_absolute_log_path "/home/cnorton/stores7/stores7.log")

(defn parse-opts
     "Using the newer cli library, parses command line args."
     [args]
     (cli args
      (required ["-host" "Informix host"] )
      (required ["-server" "Informix server"])
      (required ["-dbpath" "Full path to database directory"])
      (optional ["-port" "Informix host's service port" :default "1498"] )
      (optional ["-username" "user name"] )
      (optional ["-password" "password"] )
      (optional ["-database" "Informix host's database" :default "stores7/testdb.dbs" ] )))

(defn -main
       [& args]
       (if (= 0 (count args))
          (println "Usage: db-test -host  [-port ] -database  -dbpath  -username  -password  -server ")

       (let [opts (parse-opts args)
                   start-time (str (Date.))]

            (def informix-db {:classname "com.informix.jdbc.IfxDriver"
                              :subprotocol "informix-sqli"
                              :subname (format "//%s:%s/%s:informixserver=%s;usev5server=1;DBPATH=%s"
                                         (:host opts)
                                         (:port opts)
                                         (:database opts)
                                         (:server opts)
                                         (:dbpath opts))})

            (let [customer-list
                  (j/query informix-db
                  ["select * from customer"])]

                  (doseq [customer customer-list]
                      (println customer))))))

Leave a comment

Filed under Clojure, informix

Clojure and Perl: Noticing First Differences

This post is not intended to be a contest of one language versus another. We are using Perl for a water project for a number of pragmatic reasons, like folks working on the water project who do not know Clojure and Perl’s DBI support to name two.

Instead, this post is about something I’ve noticed, having used Clojure on a few small projects, and now returning, like Kellog’s Corn Flakes, to Perl again for the first time (since 2000, and then again in 2003).

I am re-writing three major Informix 4GL programs in Perl. They rely heavily on Perl’s DBI, and hence need to store a lot of intermediate data. So, there are quite a few module and subroutine scope variables. For me, the striking difference between Perl (and perhaps languages like it, including 4GL, VB, and so on) and Clojure is my Clojure programs don’t seem to need variables, other than global vars and data bound in let statements.

I believe my appreciation for Clojure’s immutable data is as full as it can be for someone who has worked with the language for a couple of years, so I appreciate that you cannot initialize a variable and modify it. The design of my Clojure programs always was different, despite the fact I could have bound a lot of let variables wherever I needed them, but I just never needed to do that.

The data seemed to come and go. My Clojure programs read in data; manipulate that data, make network I/O calls using that data; and then write some of that input data and new data out to disk.

When I first started learning Clojure, the luminaries said my views of designing would change, and I believe they have.

1 Comment

Filed under Clojure, Perl

Transitioning To Sequences

Problem #157 in 4Clojure.com is listed as a very simple problem. Despite having used Clojure’s map function a lot, I saw the solution to this problem recursively using loop and recur, by walking through each element of the function and determining its count. The following solution came from http://blog.qinjian.me/2012/12/21/4clojure_solutions/ . Look for #157 in the midst of quite a few solutions.


(fn __[coll]
  (loop [x (- (count coll) 1)
      l []]
  (if (>= x 0)
    (recur (- x 1)
        (conj l (list (nth coll x) x)))
    (reverse l))))

This solution makes more sense to me than this solution.


#(map list % (range))

It just doesn’t look as obvious. But the prevailing wisdom is to use Clojure’s sequence functions to handle problems like this.

8 Comments

Filed under Clojure

When Clojure Is Not Flashy

Over the past two weeks as I have prepared for a nice long rest, I wound up mostly cleaning up BASH scripts and their Informix 4GL counterpart programs. The changes were made to simplify sending data to and receiving results back from our Registry of Motor Vehicles. While not as interesting or as flashy as working with Clojure, the changes were well needed, because they involved ease of use, reliability, and simplification. To me, it is just fine to have a good cleanup effort, even if it is for an over twenty-five year old application.

Finally, I was able to spend a little time finishing up enhancements to a Clojure program that splits up real-estate assessment data, and this got me thinking.

Working with Clojure is not a good thing just because it is a Lisp dialect and programming in Lisp has always been one of my goals.

Working with Clojure is not a good thing, because it is a functional programming language or even because it is a JVM language. As it turns out the only serious Java I encountered was a Visual Cafe application that was the Vinca/Legato/EMC Co-Standby For Windows configuration application.

Working with Clojure is not a good thing, because it is an up and coming language, though I admit that is part of what drew me to learn it.

And working with Clojure is not a good thing, because using the languages encourages writing small discernible functions,  C and shell scripts on Unix encouraged writing small, well written C programs years ago.

Working with Clojure is a not good thing specifically for any of those reasons , but is a great thing, because it is possible to make a change in one area and not break something due to an accidental side-effect that could more easily occur in a language that supports mutable data structures.

This reason is not glamorous or flashy, but sometimes not having things blow up and go to pieces is better than temporary flash and glitz.

Instead Clojure can be a great tool for a one-person band, because it isn’t flashy and its constructs allow for reliability, when there is not a lot of time to ensure safety or reliability.

Leave a comment

Filed under Clojure

The 2013 Clojure Cup

Whether I can write software in 48 hours for the Clojure Cup is one thing — it’s a challenge some days to wake up — but at least I can promote it, so that I will do.

If some wonderful municipal idea comes to me, I’ll enter something. By September I will be converting a 25-year-old tax/utility collection system to calculate, adjust, and print quarterly water bills. This will be interesting.

Leave a comment

Filed under Clojure

Clojure Programming Revisited

At the time I started learning Clojure — almost two years ago — some Clojure books existed, like Programming Clojure, Practical Clojure,  and The Joy of Clojure. O’Reilly’s Clojure Programming by Chas Emeric, Brian Karper, and Christopher Grand was still being written. Of the earliest books, I like Joy of Clojure the best, because, although it does not cover a wide swath of material, it is very insightful.

In that time, I have written three medium-sized data transformation projects in Clojure, and now realize it is time to go apply more sophisticated modalities like synchronization, despite the fact that most of my work consists of very linear process step execution.

I’ve started re-reading Clojure Programming and discovered something quite nice about it. It serves quite well not only as a teaching source, but as dictionary, topic lookup, source, as well. The topics are fairly well covered, and seem as fresh today as they were when the book came out.

Leave a comment

Filed under Clojure