Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call Clojure Macros from Java?

Is there anyway to call Clojure macros from Java?

Here is what I am trying to do:

RT.var("clojure.core", "require").invoke(Symbol.create("clojure.contrib.prxml"));
Var prxml = RT.var("clojure.contrib.prxml", "prxml");
Var withOutStr = RT.var("clojure.core", "with-out-str");
String stringXML = (String) withOutStr.invoke((prxml.invoke("[:Name \"Bob\"]")));

prxml writes to *out* by default which is why I need to wrap it with the macro with-out-str which returns the string.

I am getting this error:

 [java] java.lang.IllegalArgumentException: Wrong number of args (1) passed to: core$with-out-str
 [java]     at clojure.lang.AFn.throwArity(AFn.java:437)
 [java]     at clojure.lang.RestFn.invoke(RestFn.java:412)
 [java]     at clojure.lang.Var.invoke(Var.java:365)
 [java]     at JavaClojure.xml.main(Unknown Source)
like image 629
mudge Avatar asked Jul 13 '11 00:07

mudge


2 Answers

You'll have to roll your own withOutStr.

class YourClass {
    static final Var withBindings = RT.var("clojure.core", "with-bindings*");
    static final Var list = RT.var("clojure.core", "list*");
    static final Var out = RT.var("clojure.core", "*out*");
    static final Var prxml = RT.var("clojure.contrib.prxml", "prxml");

    static String withOutStr(IFn f, Object args...) {
        StringWriter wtr = new StringWriter();
        withBindings.applyTo(list.invoke(RT.map(out, wtr), f, args));
        return wtr.toString();
    }

    ...

    String stringXML = withOutStr(prxml, "[:Name \"Bob\"]");
}
like image 176
kotarak Avatar answered Oct 06 '22 01:10

kotarak


The problem is basic.

invoke (and its sister, apply) are used for functions.

Macros are not functions, so they can not be invoked. Macros need to be compiled. In normal Lisps, they could just be eval'd or macroexpanded or whatever. And in 10m of looking around, apparently Clojure doesn't have a simple RT.eval(String script) function to make this easy.

But, that's what needs to be done. You need to compile and execute this.

I saw a package that integrates Clojure with Java JSR 223, and IT has an eval (because 223 has an eval). But I don't know a) if the package is any good or b) if this is the direction you want to go.

like image 32
Will Hartung Avatar answered Oct 05 '22 23:10

Will Hartung