Got my feet wet with Clojure

I started hardcode coding on Project Plugh. I’m working on moving a bunch of Lift concepts over to Clojure as I build Lift’s comet facilities in Clojure so I can stream data to the browser.

Background… PartialFunction

In Scala, there’s a PartialFunction

The key take-away for PartialFunctions is “… is a unary function where the domain does not necessarily include all values of type A.”
 
 
The ability to test a PartialFunction to see if the domain includes a particular value is very helpful. pf.isDefinedAt(x) allows testing to see if the function is defined at a given value of x.

But a PartialFunction is a subclass of Function, so PartialFunctions can be applied:

pf(x)

The Scala compiler will take a pattern and turn it into a PartialFunction:

def pf: PartialFunction[String, Number] = 
{
  case "" => 0 // special case blank to zero
  case x if isInt(x) => x.toInt
  case x if isDouble(x) => x.toDouble
  case x if isBigInt(x) => asBigInt(x)
}

Another property of PartialFunction is they can be composed:

pf = pf1 orElse pf2 orElse pf3 // pf isDefinedAt any place 
                               // any of the partial functions are defined

We use PartialFunctions extensively in Lift to allow choosing if a particular URL should be served by Lift, if it should be served by a particular REST handler, etc. For example, defining a REST route in Lift:

serve {
  case "api" :: "user" :: AsLong(userId) :: _ GetJson _ => 
       User.find(userId).map(_.toJson)
}

As I’ve been learning Clojure in preparation for a presentation at Strange Loop and as part of a new project I’ve been working on, I am looking to bring the best things in Lift into the Clojure code I write.

Into Clojure

Clojure’s pattern matching stuff is pretty nifty. I especially like how you can extract values out of a Map (this is so much more powerful that Scala’s pattern matching, even with unapply… but I digress).

So, I wrote a macro:

(defmacro match-func [& body] `(fn [~'x] (match [~'x] ~@body)))

This creates a function that is the application of the match to a parameter, so:

((match-func [q :guard even?] (+ 1 q) [z] (* 7 z)) 33)
;; 231

Turns out the Clojure pattern matcher will extract values into unbound variables. But bound variables are tested… this means that:

((match-func [[x y]] (+ x y)) [4 5])

Turns out this is a problem because x is bound in the match-func macro… so we need to change x to something else. So, we have to change the variable x to something else:

(defmacro match-func [& body]
    "Create a function that does pattern matching."
    `(fn [x#] (match [x#] ~@body)))

isDefinedAt

So, how do we test to see if the pattern matches at a particular value?

This became a challenge for me to wrap my brain around how things are done in Clojure. How do I have a function that represents the pattern match and be able to query it to see if it’s defined at a point without invoking the computation on the right-side which can be side-effecting.

The answer is arity. Scala has functions with defined arity. Turns out that Clojure can have a single function that behaves differently depending on the arity of the invocation. Yay!

So, the macro looks like:

(defmacro match-pfunc [& body]
  "Create a partial function that does pattern matching."
  (let [rewrite (mapcat (fn [x] [(first x) true]) (partition 2 body))]
  `(fn ([x#] (match [x#] ~@body))
       ([x# y#]
         (cond
           (= :defined? x#)
           (match [y#] ~@rewrite)
           (= :body x#)
           '(~@body))))))

What this gives us is a function than can be invoked with a single parameter:

(pf 44)

And it can be invoked with 2 parameters:

(pf :defined? 44)

And I added the ability to get the body of the original so that I can add an orElse function that will actually build a new PartialFunction that is the compilation of the composed patterns so that the patterns will be compiled more efficiently.

First toe in the water

Yep. I think Clojure is pretty powerful. With macros, I’ve added one of the most amazingly powerful language feature of Scala to Clojure in a few lines. The water feels pretty good so far.
 

Reference: Got my feet wet with Clojure from our JCG partner David Pollak at the DPP’s Blog blog.
Related Whitepaper:

Java Essential Training

Author David Gassner explores Java SE (Standard Edition), the language used to build mobile apps for Android devices, enterprise server applications, and more!

The course demonstrates how to install both Java and the Eclipse IDE and dives into the particulars of programming. The course also explains the fundamentals of Java, from creating simple variables, assigning values, and declaring methods to working with strings, arrays, and subclasses; reading and writing to text files; and implementing object oriented programming concepts. Exercise files are included with the course.

Get it Now!  

Leave a Reply


3 × nine =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books