Friday, October 28, 2016

Destructuring Clojure Vector and Map

Clojure documentation describes destructuring as:


Destructuring is a way to concisely bind names to the values inside a data structure. Destructuring allows us to write more concise and readable code.

So, what does this mean?

Suppose we have a vector that contains the bridge officers found in Star Trek original series:


(def star-trek-bridge-officers [ :kirk :spock :sulu :uhura ])

To retrieve the values, we could destructure the elements this way:


(let [[a b c d ] star-trek-bridge-officers] 
    println (str a " " b " " c " " d))
;; ":kirk :spock :sulu :uhura"

What happened here was the keyword :kirk is bound to the variable a, :spock to b and so on and so forth.


Suppose we have a slightly different vector, where :sulu and :uhura belongs to another subvector:


(def star-trek-bridge-officers-2 [ :kirk :spock [:sulu :uhura]])

To retrieve the values:


(let [[a b [c d]] star-trek-bridge-officers-2] println (str a " " b " " c " " d))
;; ":kirk :spock :sulu :uhura"

If we're not interested with Spock and Uhura, we replace the variables with underscore character "_":

(let [[a _ [c _]] star-trek-bridge-officers-2] 
    println (str a " " c))

;; ":kirk :sulu"



Jim, you can't risk your life on theory!



Now, let's talk about destructuring a map.

Suppose we have a map that contains the rank and names of the crew:


(def star-trek-crew { :captain "kirk" :lt-cmd "spock" :lt-1 "sulu" :lt-2 "uhura" })

To retrieve the values by the keys:


(let [{a :captain b :lt-cmd c :lt-1 d :lt-2 } star-trek-bridge-officers] 
    println (str a " " b " " c " " d))
;; "kirk spock sulu uhura"

The variable a is bound to the value of the key :captain and b is bound to the value of the key :lt-cmd.

To complicate the map structure a bit, I'm going to add a few more members as an embedded map:


(def star-trek-officers { :captain "kirk" :lt-cmd "spock" :lt-1 "sulu" :lt-2 "uhura" 
    :non-bridge-officers {:lt-cmd-1 "scotty" :lt-cmd-2 "mccoy" :nurse "chapel"}})

To retrieve the values including the embedded map:


(let [{a :captain b :lt-cmd c :lt-1 d :lt-2 {x :lt-cmd-1 y :lt-cmd-2 z :nurse} 
    :non-bridge-officers} star-trek-officers] 
        println (str a " " b " " c " " d " " x " " y " " z))
;; "kirk spock sulu uhura scotty mccoy chapel"

As you can see, we need to use :non-bridge-officers as the key to refer to the embedded map.


We all have our darker side. We need it; it's half of what we are.
        It's not really ugly, it's human.


Saturday, October 22, 2016

Clojure Plan, Map and Courage

This is one of those moments when the computer says NO!

Let's look at the interesting nature of Clojure's map function.

(defn foo[filenames]
    (map #(touchFile (str "/tmp/" %)) filenames))

Suppose we have a pre-existing function called touchFile that creates an empty file.

This foo function never created any files when called. I must have made a mistake with the directory path or perhaps my filesystem ran out of space or perhaps a bug somewhere in my touchFile function or perhaps...

Hang on, my test code for touchFile passes without any problem!

An attempt to prove something is wrong with the map call....

(defn foo[filenames]
    (map #(println (str "/tmp/" %)) filenames))

And nothing was printed out on my screen!

Something really sinister is going on here...

All you need is the plan, the road map, and the courage to press on to your destination.


After going back to the docs, it mentioned that "map returns a lazy sequence of...". Did you just hear the penny dropped?

So, the fix here is to invoke doall to force the map to evaluate each items immediately.

(defn foo[filenames]
    (doall (map #(touchFile (str "/tmp/" %)) filenames)))

Yay it worked!



Looking at a simple problem at 2 in the morning doesn't help a lot. It's probably time for me to hit the Zs.


Friday, October 14, 2016

In Search For A Better CI/CD

This is going to be an exciting time!

Imagine me, writing me first Clojure app!

I'm halfway through writing my first Clojure program called "relman", short for "Release Manager".
It's a simple CLI application to help me deploy specific WAR files to a dockerised Tomcat. 

The recipe here is a simple pull deployment (unless I've hit unforeseen issues - fingers crossed).

Firstly, I've configured my Jenkins build to rename any successful elwood-parent builds to <feature>-<issue number>-<issue description>-<#build number>.war and copy this to a mounted volume shared with Tomcat.

Secondly, running relman on host to copy the war file as ROOT to the designated Tomcat directory mounted as "/webapp".

Thirdly, umm.. I think that's it. Trying to keep the solution simple.

This POC worked by manually copying the file across directories, so technically this idea should work!

Furthermore, I think this recipe is universal and applicable when I use different Git branches whenever Jenkins kicks in.

Elwood Continuous Integration and Delivery

As with relman in Clojure, this is a work in progress but I think I'm not far off from my end goal.

In summary, this is my first step to get CI/CD working and it's by no means an end to this exciting journey!

And the quest for CI/CD continues... (Clojure included)

Wednesday, October 5, 2016

Clojure Exercise #1: Bend My Mind With MapSet

Write a function, mapset, that works like map except the return value is a set:
(mapset inc [1 1 2 2])
;=> #{2 3}


Answer:

(defn mapset [fn elements]
(let [uniq (into #{} elements)]
(set (map fn uniq))))



How can I write a piece of code without a unit test?

(deftest mapset-test
(is (= #{ 2 3 } (mapset inc [1 1 2 2]))))



Invoking mapset:

(mapset inc [1 1 2 2])
;=> #{3 2}

Tuesday, October 4, 2016

I Keep Coming Back to the Land Of Lisp

Don't ask me why. For some reason, I keep coming back to the Land of Lisp.

A few weeks ago, I was reading a few chapters about Common Lisp before I went to bed.
I remember vividly on one particular night, my mind was mumbling about the cryptic CAR, CDR, CDAR, CADR operations repeatedly, while looking at an unknown rectangular block chopped off from the top.

Well, the good thing is - this isn't one of Freddy Krueger's episode.


Lisp has been around for quite some time and to think about this old language coming back to life in the modern times or as an incarnation is exciting.

Welcome Clojure!


I hear people complained about the excessive (((((parenthesis))))) that comes with it. True, but has anyone complained about excessive semis;colons;and;{braces{around{blocks}}} from other programming languages? (No Visual Basic 6 please)


Though quite new to Clojure, I thought of trying a few simple things to see how it tastes like.

To compute for an extended price of an imaginary item (I was told that I should use a map to represent the properties of an item):

(defn line-extended [{qty :qty price :price discount :discount}]
   (* (- price discount) qty))

Simple enough.


Next is what I find Clojure interesting.

Suppose I need to sum all quantity, price and discount:

(defn line-items-summary [items]
   (apply merge-with + (for [item items]
   select-keys item [:qty :price :discount]))))

The code performs a loop for each item, add the quantity, price and discount and returns the sum of these properties.

So invoking this function as follows:

(line-items-summary [
    {:qty 1 :price 10 :discount 2}
    {:qty 2 :price 1000 :discount 200}])
Returns:
{:qty 3, :price 1010, :discount 202}


The syntax looks simple, elegant and most of all appealing. 

To sum up the three adjectives - it's POWERFUL!