Kurser i Domain-Driven Design - VĂ¥ren 2012




Monday, August 10, 2009

Laziness IS a Virtue of a Programmer

As it turns out, laziness is a virtue of a programmer...

It is with particular joy I am rediscovering the programming paradigm that once introduced me to the art of software development: Functional programming. I begun my university studies almost 15 years ago. I initially planned to study biotechnology, but for different reasons I ended up with a M Sc degree in Information Technology Engineering instead. I had not really been doing any serious computer programming prior to my university studies, and the first course they threw at us was this monstrous thing called "Program Construction". It sure was a lot of work, but it built a great foundation for our further studies. And it was all tought in ML. 10+ years of Java followed. March this year I attended QCon London to give a tutorial on the DDDSample app, and also had the opportunity to listen to Rich Hickey give a presentation on Clojure. Since then I have slowly been rediscovering the beauty of functional programming; map, reduce/fold, higher-order functions, recursion, and more.

As an example, let's look at Clojure's lazy sequences:

This gives us a lazy sequence of all whole numbers:
(def numbers (iterate inc 1))

If executed it will define a lazy sequence, i.e. its elements will not be evaluated until needed. This is a good thing in this case since this sequence is infinite.

We can now use this infinite sequence, for example by calling:
(take 10 (drop 1000 numbers))

which will return the following (lazy) sequence:
(1001 1002 1003 1004 1005 1006 1007 1008 1009 1010)

Or why not take all the even numbers by filtering the sequence:
(take 10 (filter even? numbers))

returns:
(2 4 6 8 10 12 14 16 18 20)

I think this is pretty sweet!

For an upcoming PNEHM! article I needed to generate data sets of arbitrary sizes consisting of random letters a-z, so I did this:
(def s "abcdefghijklmnopqrstuvwxyz")

(def data-set
(repeatedly
#(nth s (rand-int (dec (count s))))))

From which I can take whatever number of random characters I like and do something with, for instance write 100 chars to file as a string:
(use 'clojure.contrib.duck-streams)
(spit "data-set.txt" (apply str (take 100 data-set)))

Note that the sequence is cached, so I will get the same characters each time (take 100 ...) is called. This may not be what you want. Converting the def to a no-args function, we can call it repeatedly and get different lazy sequences:
(defn data-set []
(repeatedly
#(nth s (rand-int (dec (count s))))))

And do:
(take 100 (data-set))

One final example, a function to calculate the Fibonacci sequence, from http://en.wikibooks.org/wiki/Clojure_Programming/Examples/Lazy_Fibonacci:
(defn fib-seq []
((fn rfib [a b]
(cons a (lazy-seq (rfib b (+ a b)))))
0 1))

(take 10 (fib-seq))

Gives:
(0 1 1 2 3 5 8 13 21 34)

No comments: