簡體   English   中英

如何從 Java 調用 Clojure 宏?

[英]How to call Clojure Macros from Java?

有沒有辦法從 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 默認寫入 *out*,這就是為什么我需要用返回字符串的宏 with-out-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)

您必須自己使用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\"]");
}

問題是基本的。

調用(及其姐妹應用)用於函數。

宏不是函數,因此不能調用它們。 需要編譯宏。 在普通的 Lisp 中,它們可以被評估或宏擴展或其他。 在 10m 的環顧中,顯然 Clojure 沒有簡單的 RT.eval(String script) function 來簡化此操作。

但是,這就是需要做的。 您需要編譯並執行它。

我看到一個package集成了 Clojure 和 Java JSR 223,它有一個 eval(因為 223 有一個 eval)。 但我不知道 a)package 是否好,或者 b)如果這是您想要的 go 的方向。

免責聲明:我對 clojure 知之甚少(我的經驗是使用其他函數式語言和 Java)

然而,我的直覺說問題出在prxml.invoke()周圍。 這里的想法是該語句評估得太快,並將結果發送到 withOutStr (而不是讓 withOutStr 評估它)。

僅查看在線資源...尤其是RTVarAFn以及 clojure doc for with-out-str我會嘗試以下內容:

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

編輯:我還懷疑它能夠從 java 調用 clojure 宏,否則 Var 上的 isMacro() function 似乎相當愚蠢

編輯 2:下載 clojure,並嘗試過...不起作用所以暫時忽略它。

編輯 3:with-out-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));

has an output of: [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:通過編譯器和更多代碼,似乎宏實際上有 2 個隱藏參數。 查看提交 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__)))

這似乎更有希望,但它仍然需要評估在編譯器中似乎有特殊情況的 let 表達式。

如果要從 C# 或 Java 執行 Clojure 代碼,請使用 Clojure 的加載字符串ZC1C4252674C1ZA98。 這將采用一個普通字符串並完全按照您在 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();
        }
    }

您可以在此處查看示例程序的完整版本。 它包含大量示例代碼來演示 Clojure 互操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM