【问题标题】:Clojure evaluating string variable as a symbol, is this use of read-string okay?Clojure 将字符串变量评估为符号,这种使用读取字符串可以吗?
【发布时间】:2018-11-29 03:12:38
【问题描述】:

我可以使用memfn 创建一个调用 java 函数的 clojure 函数。

(macroexpand '(memfn startsWith prefix))
=> (fn* ([target2780 prefix] (. target2780 (startsWith prefix))))
((memfn startsWith prefix) "abc" "a")
=> true

memfn 要求函数名是符号。我想知道是否可以编写一个宏来调用名称以字符串形式提供的任意方法。也就是说,我希望能够调用以下内容:

(def fn-name "startsWith")
=> #'user/fn-name
(macroexpand '(memfn' fn-name "prefix"))
=> (fn* ([target2780 prefix] (. target2780 (startsWith prefix))))
((memfn fn-name "prefix") "abc" "a")
=> true

我能想到的唯一方法是使用read-string

(defmacro memfn' [fn-name arg-name]
  `(memfn ~(read-string fn-name) ~arg-name))

编辑:使用 read-string 和 eval 的版本实际上按我想要的方式工作。

(defn memfn' [fn-name arg-name]
  (eval (read-string (str "(memfn " fn-name " " arg-name ")"))))

我是否缺少一个基本的宏构建工具来获取符号引用的字符串并将其转换为文字而无需执行代码,就像read-string 可能的那样?

感谢您的任何想法!

【问题讨论】:

  • 我认为深入了解您如何想象使用这样的功能会很有用。当人们开始需要eval 来进行这种元编程时,通常会有一些替代解决方案可以实现相同的目标,但需要不同的方法。例如,您有时可以让一个变量在全局范围内,并在 let 内定义可以通过词法范围访问该定义的宏,而不是定义一个 var,然后基于该 var 单独创建函数。
  • 你不需要读取字符串,'clojure.core/symbol'函数可用于将字符串转换为符号

标签: clojure lisp-macros


【解决方案1】:

无论有没有读取字符串,都无法做到这一点。您提出的解决方案不起作用。您真正想要区分的不是字符串和符号,而是运行时数据和编译时文字。宏不会评估它们收到的参数,因此即使fn-name 是值为"startsWith" 的var 的名称,memfn(或您的memfn' 宏)也只会看到fn-name

【讨论】:

  • 你是对的,发布了一个带有eval 的版本,它确实有效。似乎这至少是弥合运行时编译时间差距的一种方法。有没有办法在没有评估的情况下做到这一点,或者只是限制需要evald 的部分?
【解决方案2】:

如果您对调用 java 方法感兴趣,那么您可以依赖 java.lang.reflect.Method 及其调用方法。

这样的东西应该适用于无参数方法并且不需要宏。

(defn memfn' [m]
  (fn [o] (.invoke (.getMethod (-> o .getClass) m nil) o nil)))

((memfn' "length") "clojure")
;=>7

【讨论】:

    猜你喜欢
    • 2022-01-19
    • 1970-01-01
    • 2014-08-31
    • 1970-01-01
    • 1970-01-01
    • 2019-07-09
    • 2020-04-20
    • 1970-01-01
    相关资源
    最近更新 更多