Передача объектов из Java в Clojure Eval - PullRequest
2 голосов
/ 10 октября 2011

Я вызываю Clojure из Java и вызываю eval для переданной строки. Код Java будет содержать объекты, а клиентский код может указывать строки кода Clojure для запуска на объекте. Я знаю, как вызывать код Clojure из Java, но как передать переменную в?

Вот что у меня есть. Во-первых, простой объект для работы:

public class Helloer {
    public String getGreeting() { return "Hello"; }
}

Затем некоторый шаблонный код для вызова метода Clojure.

public static String call(Helloer helloer, String expression) throws Exception {
    RT.loadResourceScript("EvalObject.clj");
    final Var schrodEval = RT.var("eval-object", "eval-string");
    final String result = (String) schrodEval.invoke(expression, helloer);
    return result;
}

Но потом я застреваю в коде Clojure. Объект передается в порядке, но как передать значение в eval?

Вот что я пробовал:

(ns eval-object)

(defn eval-string [string this]
  (eval (read-string string)))

(defn eval-string2 [string value]
  (def this)
  (binding [this value]
    (eval (read-string string))))

(defn eval-string3 [string value]
  (def this)
  (eval (list 'binding (vector 'this 5) (read-string string))))

Они дают:

java.lang.Exception: Unable to resolve symbol: this in this context (NO_SOURCE_FILE:0)

Итак, я попытался создать связующее предложение, которое определяет this:

(defn eval-string4 [string value]
  (def this)
  (eval (list 'do (list 'defonce 'this nil)
        (list 'binding (vector 'this value) (read-string string)))))

Но теперь я получаю:

java.lang.RuntimeException: Can't embed object in code, maybe print-dup not defined: Helloer@638bd7f1 (NO_SOURCE_FILE:0)

Я что-то упустил? Можно ли передавать объекты из Java в Clojure и в eval?

Ответы [ 2 ]

3 голосов
/ 10 октября 2011

Не совсем понятно, что вы подразумеваете под «передать объекты в eval».Возможно, вы могли бы уточнить цель немного больше?

Однако, возможно, вы ищете что-то вроде этого:

(defn call-eval [helloer]
  (eval `(.getGreeting ~helloer)))

(call-eval some-helloer)
=> "Hello"

Несколько вещей, на которые стоит обратить внимание:

  • Когда вы делаете eval, вам нужно заключить в кавычки форму
  • Чтобы передать "объект", вам нужно снять его с кавычек (~) в этой форме, чтобы объект использовался непосредственно, а не просто как символ
  • Вам не требуется eval для этого, поскольку (.getGreeting helloer) работает так же хорошо (и гораздо болееэффективен, поскольку не требует компиляции формы. Обычно, eval необходим только тогда, когда вы динамически генерируете новый код во время выполнения или если вы хотите прочитать и принять произвольный код в качестве ввода (например, сам REPL).
2 голосов
/ 11 октября 2011

Оказывается, сообщение об ошибке было правильным.Мне нужно было определить print-dup.Я реализовал простой поиск идентификатора для класса Helloer и определил print-dup как:

(defmethod print-dup com.ziroby.Helloer [h stream]
  (.write stream "#=(com.ziroby.Helloer/getById ")
  (.write stream (str (.getId h)))
  (.write stream ")"))

Очевидно, что Clojure требуется какой-то способ напечатать объект, чтобы иметь возможность поместить его в оператор eval.print-dup создает инструкцию Clojure для «создания» объекта путем его поиска с помощью Helloer.getById (который просто ищет объект в хэш-карте).

Как говорит @mikera, вам нужно только перейтичерез эти обручи, если вы принимаете произвольный код от вашего вызывающего или динамически генерируете код.

...