Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何获得函数';Clojure中的字符串是什么?_Clojure - Fatal编程技术网

如何获得函数';Clojure中的字符串是什么?

如何获得函数';Clojure中的字符串是什么?,clojure,Clojure,如何在Clojure中以字符串形式获取函数名 到目前为止,我所讲的内容看起来都不地道: (defn fn-name [f] (first (re-find #"(?<=\$)([^@]+)(?=@)" (str f)))) (defn foo []) (fn-name foo) ;; returns "foo" 对于使用defn表单定义的函数: user> (-> #'map meta :name) map user> (defn nothing [&

如何在Clojure中以字符串形式获取函数名

到目前为止,我所讲的内容看起来都不地道:

(defn fn-name
  [f]
  (first (re-find #"(?<=\$)([^@]+)(?=@)" (str f))))

(defn foo [])

(fn-name foo) ;; returns "foo"

对于使用
defn
表单定义的函数:

user> (-> #'map meta :name)
map
user> (defn nothing [& _])
#'user/nothing
user> (-> #'nothing meta :name)
nothing
这需要访问var,而不仅仅是var持有的函数值。

编辑:我找到了一个更好的方法 Clojure包含一个名为demunge的函数。因此,与其重新发明轮子,不如使用它;)

或者如果你想要一个漂亮的版本

(defn- pretty-demunge
  [fn-object]
  (let [dem-fn (demunge (str fn-object))
        pretty (second (re-find #"(.*?\/.*?)[\-\-|@].*" dem-fn))]
    (if pretty pretty dem-fn)))

(pretty-demunge map?);; "clojure.core/map?"

我认为有一种更干净的方法可以做到这一点。我遇到了同样的问题,想知道作为函数中的参数得到的函数的名称。我无法使用宏,因为我需要映射它,所以这里是我得到的:(假设字符串?函数是否作为参数传递)

当然,这不是一个完整的解决方案,但我相信你可以从这里解决问题。基本上Clojure会将函数名转换为它可以使用的名称。因此,基本思路显然是:你需要解开它! 这很容易,因为str可以处理任何函数:D,返回函数的损坏名称

顺便说一下,这也行

(def foo string?)
(clojure.string/replace (second (re-find #"^.+\$(.+)\@.+$" (str foo)))
                        #"\_QMARK\_" "?")
; string?

玩得开心

我在评论中建议改进@carocad的答案。因为我也需要这样做,而且我需要在
clj
cljs
中这样做,所以我想到了以下几点:

(ns my-ns.core
  (:require [clojure.string :as s]
            #?(:clj [clojure.main :refer [demunge]])))

(defn fn-name
  [f]
  #?(:clj
      (as-> (str f) $
            (demunge $)
            (or (re-find #"(.+)--\d+@" $)
                (re-find #"(.+)@" $))
            (last $))
     :cljs
      (as-> (.-name f) $
            (demunge $)
            (s/split $ #"/")
            ((juxt butlast last) $)
            (update $ 0 #(s/join "." %))
            (s/join "/" $))))
请注意,
cljs.core
有自己的
demange
内置,无法访问
clojure.main


编辑

请注意,如果执行
(使用meta a-fn{…})
,它将在clojure中返回
clojure.lang.AFunction
,这将隐藏底层名称和命名空间信息。可能还有其他类似的情况,我不确定。使用
fn
literal表单,您可以执行
^{…}(fn…
而不是
(使用meta(fn…{…})
,并且它不会返回
clojure.lang.AFunction
,但该解决方法无法使用预定义函数。我还没有在clojurescript中测试过这一切,看看它是否以同样的方式工作

还请注意,clojure中的匿名函数总是以
fn
结尾,就像
中的“my ns.core/fn”
一样。通常,这些函数的末尾会有一个“
”--[0-9]+”
,但上面的正则表达式删除了这个选项。您可以修改上面的函数,并对匿名函数进行例外。只要lambda具有内部名称,就会使用该名称,例如:

(fn-name (fn abc [x] x)) ;;=> "my-ns.core/abc"

同样,我还没有在clojurescript中测试过这些注释。

在这种情况下,对var的访问是一个限制,因为这意味着我无法将这些代码封装到函数中。但是,根据您的提示(以及其他地方的提示),我创建了一个宏来完成这项工作。见我编辑的问题。您对这种解决方案有何看法?它看起来很合理,只要您没有像
(fn[f](fn name f))
这样的场景,因为var将在参数求值时解析。确切地说,我知道这一点,我想知道是否可以通过使用“完全限定”函数名传递宏来解决这个问题。什么是#map?我知道#{}for set和'is quote.
#'foo
是一个读卡器宏,它扩展到
(var foo)
-它访问命名空间拥有的可变变量,而不是存储在其中的值。一般来说,
#
为函数引入读取器宏
#()
#{}
为集合引入读取器宏,
#inst
为日期引入读取器宏,等等。这个宏有什么意义?它只能处理文本,如
(fn name inc)
,而
(let[f inc](fn name f))
将失败。如果您按字面意思键入
inc
,只需键入
“inc”
,然后保存一些字符!这就是它的局限性。正如@noisesmith提到的,它适用于同一名称空间中的
defn
s。我不选择同时以字符串形式键入函数名。我正在寻找如何获取作为参数传递的任何函数的名称。这样的函数有名称吗?没有。正如Sean Devlin()所写,函数对象没有名称。只有函数绑定到的符号才有一个。我本来可以把我的问题说得更清楚的。哦,我刚刚意识到这几乎和你一开始的情况一样。我不明白它有什么问题。对我来说,它看起来非常好。正则表达式(.*?\/.[\-\-\-\-\@].*.在第一个
-
处停止。例如,
(pretty demange assoc in)
返回
clojure.core/assoc
。如果您只得到
@
之前的所有内容,我认为主要的边缘情况是字符串以
#“-[0-9]+”
结尾(这是由lambdas引起的,例如当函数由
定义时(def my fn(fn…)
)。因此,您需要检查两种可能性:
(last(或(re-find#“(.+)--\d++”dem-fn)(re-find#“(.+)@”dem-fn))
(def foo string?)
(clojure.string/replace (second (re-find #"^.+\$(.+)\@.+$" (str foo)))
                        #"\_QMARK\_" "?")
; string?
(ns my-ns.core
  (:require [clojure.string :as s]
            #?(:clj [clojure.main :refer [demunge]])))

(defn fn-name
  [f]
  #?(:clj
      (as-> (str f) $
            (demunge $)
            (or (re-find #"(.+)--\d+@" $)
                (re-find #"(.+)@" $))
            (last $))
     :cljs
      (as-> (.-name f) $
            (demunge $)
            (s/split $ #"/")
            ((juxt butlast last) $)
            (update $ 0 #(s/join "." %))
            (s/join "/" $))))
(fn-name (fn abc [x] x)) ;;=> "my-ns.core/abc"