2011-07-13 66 views
10

有沒有辦法從Java調用Clojure宏?如何從Java調用Clojure宏?

這裏就是我想要做:

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默認這就是爲什麼我需要帶出-STR它返回字符串宏來包裝它寫到*出*。

我收到此錯誤:

[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) 
+0

你甚至可以從Java調用宏嗎?我對Clojure瞭解不多,但在Lisp中,宏在編譯代碼之前由讀者進行評估。如果Clojure的方式相同,那麼從Java調用可能爲時已晚。宏在Clojure中何時擴展? –

+1

是的,你可以從Java調用Clojure宏,但是你需要調用Clojure閱讀器(以便編譯器被調用並擴展宏),而不是特定的函數(因爲函數已經被編譯!)。可能值得檢查這個問題的答案:http://stackoverflow.com/questions/2181774/calling-clojure-from-java – mikera

+0

mikera,我認爲你是在一些東西。我想知道是否有一種很好的方法可以在Java中的宏中調用clojure reader。 – mudge

回答

1

免責聲明:我不是很瞭解的Clojure(我的經驗是與其他功能的語言和Java)

我的直覺卻表示,問題是各地prxml.invoke()。這裏的想法是,該語句過早評估,並將結果發送給OutStr(而不是讓withOutStr評估它)。在源

尋找在線獨自...特別是RTVar & AFn以及Clojure的文檔的with-out-str我會嘗試沿着線的東西:

String stringXML = (String) withOutStr.invoke(RT.list(prxml,"[:Name \"Bob\"]")); 

編輯:此外,我會懷疑它能夠從java中調用clojure宏,否則Var上的isMacro()函數看起來相當愚蠢......

編輯2:下載的clojure,並嘗試過......沒有工作,所以現在就忽略它。

編輯3:出-STR顯然需要2個參數,以便:

final Cons consXML = (Cons) withOutStr.invoke(prxml, RT.list("[:Name \"Bob\"]")); 
final Object[] objs = RT.seqToArray(consXML); 
System.out.println(Arrays.toString(objs)); 

具有的輸出:[clojure.core/let, [s__4095__auto__ (new java.io.StringWriter)], (clojure.core/binding [clojure.core/*out* s__4095__auto__] (clojure.core/str s__4095__auto__))]

我不知道這是否會評估到一些有用的東西,或不(不知道如果我對綁定正確,則必須弄清楚如何通過Java來評估這些缺點。

編輯4:通過編譯器和更多代碼查看,看起來宏實際上有兩個隱藏參數。請參見the commit 17a8c90

複製的編譯器我有方法:

final ISeq form = RT.cons(withOutStr, RT.cons(prxml, RT.cons("[:Name \"Bob\"]", null))); 
final Cons consXML = (Cons) withOutStr.applyTo(RT.cons(form, RT.cons(null, form.next()))); 
System.out.println(consXML.toString()); 
// Output: (clojure.core/let [s__4095__auto__ (new java.io.StringWriter)] (clojure.core/binding [clojure.core/*out* s__4095__auto__] #'clojure.contrib.prxml/prxml "[:Name \"Bob\"]" (clojure.core/str s__4095__auto__))) 

這似乎更有前途了一點,但它仍然需要讓表情似乎有編譯器的特殊情況的評估。

5

問題是基本的。

invoke(及其姐妹,申請)用於功能。

宏不是函數,所以它們不能被調用。宏需要被編譯。在正常的Lisps中,他們可以被評估或宏觀擴展或任何其他。在10米的環視中,顯然Clojure沒有一個簡單的RT.eval(字符串腳本)函數來簡化它。

但是,這是需要做的。您需要編譯並執行此操作。

我看到一個集成了Clojure和Java JSR 223的package,而IT有一個eval(因爲223有一個eval)。但我不知道a)如果包裹是好的,或者b)如果這是你想要去的方向。

+1

我發現我可以使用下面的語言來獲得Java中的Clojure閱讀器和評估器:RT.var(「clojure.core」,「eval」)。invoke(RT.var(「clojure.core」,「read-string」 ).invoke(「Clojure string here。」) – mudge

+0

啊優秀。是的,我很驚訝我找不到類似RT的簡單電話,但這正是你想要做的。 –

7

您將不得不使用OutStr自己推出。

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\"]"); 
} 
+0

是的,這很好,謝謝! – mudge

0

如果你想從C#或Java執行Clojure的代碼,使用Clojure的load-string功能。這將需要一個普通的字符串,並執行它,就像你在REPL中鍵入字符串一樣。這包括處理宏。

下面是C#代碼的簡短版本。 Java版本不會離得太遠。

private static readonly IFn LOAD_STRING = Clojure.var("clojure.core", "load-string"); 

    private void executeButton_Click(object sender, EventArgs e) 
    { 
     try 
     { 
      object result = LOAD_STRING.invoke(sourceTextBox.Text); 
      if (null == result) 
       resultTextBox.Text = "null"; 
      else 
       resultTextBox.Text = result.ToString() + " (" + result.GetType().Name + ")"; 
     } 
     catch (Exception ex) 
     { 
      resultTextBox.Text = ex.ToString(); 
     } 
    } 

您可以看到完整版本的示例程序here。它包含了很多示例代碼來演示Clojure互操作。