10

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)
4

4 に答える 4

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\"]");
}
于 2011-07-13T06:31:16.610 に答える
5

問題は基本です。

関数には invoke (およびその姉妹である apply) が使用されます。

マクロは関数ではないため、呼び出すことはできません。マクロはコンパイルする必要があります。通常の Lisp では、それらは評価されたり、マクロ展開されたりするだけで済みます。そして、10 分間見回したところ、どうやら Clojure には、これを簡単にするための単純な RT.eval(String script) 関数がありません。

しかし、それは行う必要があることです。これをコンパイルして実行する必要があります。

Clojure を Java JSR 223 と統合するパッケージを見ましたが、IT には eval があります (223 には eval があるため)。しかし、a) パッケージが適切かどうか、b) これがあなたの望む方向性かどうかはわかりません。

于 2011-07-13T03:54:38.537 に答える
1

免責事項: 私は clojure についてほとんど知りません (私の経験は他の関数型言語と Java でした)。

しかし、私の本能は、問題は周りにあると言いprxml.invoke()ます。ここで考えられるのは、そのステートメントの評価が早すぎて、(withOutStr に評価させる代わりに) 結果を withOutStr に送信するということです。

ソースをオンラインで単独で見ると...特にRTVar & AFn 、およびwith-out-strの clojure doc を見ると、次の行に沿って何かを試してみます。

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

編集: また、java から clojure マクロを呼び出すことができると思われます。それ以外の場合、Var の isMacro() 関数はかなりばかげているようです...

編集 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));

次の出力があります。[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 式の評価が必要です。

于 2011-07-13T01:50:25.087 に答える
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();
        }
    }

サンプル プログラムの完全版は、こちらでご覧いただけます。Clojure の相互運用性を示すためのサンプル コードが多数含まれています。

于 2016-05-08T16:19:33.110 に答える