繁体   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