Clojure’s Java interop in Java

I should rather refrain from announcing the blog entry Thinking functional programming with Map and Fold in your everyday Java as it wasn’t at all useful from the point of a person who’s aiming at learning functional programming, however, on the contrary, it did a great job of encouraging me to try out Clojure’s Java interop from Java. I knew the theory but lacked practice.

WARNING: If you’re new to Clojure and functional programming, and want to learn either/both, the blog entry shall not be useful.

It took me quite a few mental cycles before I realized I’d merely need (Eclipse) IDE and clojure-1.3.0.jar. Nothing else’s needed. I’m explicitly saying it to invite you to give it a try yourself.

The very first example was as follows:

package pl.japila.clojure;

import java.util.Arrays;
import java.util.Iterator;

import clojure.lang.IFn;
import clojure.lang.LazySeq;
import clojure.lang.RT;

public class Main {

    public static void main(String[] args) {
        IFn map = RT.var("clojure.core", "map");
        IFn inc = RT.var("clojure.core", "inc");
        LazySeq seq = (LazySeq) map.invoke(inc, new int[] { 1, 2, 3 });
        System.out.println(Arrays.asList(seq.toArray()));
    }

}

All it does is to increment (the function inc) each and every element in the int array. That’s how the function map works after all – it applies a function to the elements of a sequence and returns another sequence (remember that the data structures in Clojure are immutable).

And I was about to have left the exercise aside when I decided to create the other methods of the blog entry.

Here are the other methods with Clojure embedded. It’s a mixture of using Clojure’s clojure.lang.RT to build “s-expressions” as well as using Clojure’s clojure.lang.Compiler to have them typed in as if they were written in a Clojure script.

package pl.japila.clojure;

import java.io.StringReader;
import java.util.Arrays;
import java.util.List;

import clojure.lang.Compiler;
import clojure.lang.IFn;
import clojure.lang.LazySeq;
import clojure.lang.RT;

public class Main {

    public static void main(String[] args) {
        List<Double> amounts = Arrays.asList(2.7, 5.9, 2.2);

        System.out.println(totalAmount(amounts)); // returns 10.8
        System.out.println(addVAT(amounts, 19 / 100d)); // returns [3.213,
                                                        // 7.021, 2.618]
    }

    public final static List<?> addVAT(List<Double> amounts, double rate) {
        IFn map = RT.var("clojure.core", "map");

        String fn = String.format("(fn [r] (* r (inc %s)))", rate);
        IFn addVAT = (IFn) Compiler.load(new StringReader(fn));

        LazySeq seq = (LazySeq) map.invoke(addVAT, amounts);

        return (List<?>) Arrays.asList(seq.toArray());
    }

    public final static double totalAmount(List<Double> amounts) {
        IFn reduce = RT.var("clojure.core", "reduce");
        IFn plus = RT.var("clojure.core", "+");
        return (Double) reduce.invoke(plus, amounts);
    }

}

The blog entry Embedding Clojure helped me a lot. I bet I wouldn’t have been able to do the task without it.

BTW, I’ll leave convertCurrency as an exercise.

Be Sociable, Share!
This entry was posted in Languages.

Leave a Reply

%d bloggers like this: