Intellij idea 无法在没有扩展错误的情况下执行Clojure宏
我正在编写一个宏,它查看给定符号上的元数据并删除任何非关键字的条目,即关键字名称不以:开头Intellij idea 无法在没有扩展错误的情况下执行Clojure宏,intellij-idea,clojure,metadata,cursive,Intellij Idea,Clojure,Metadata,Cursive,我正在编写一个宏,它查看给定符号上的元数据并删除任何非关键字的条目,即关键字名称不以:开头 (meta (var X)) ;; Here's the metadata for testing... => {:line 1, :column 1, :file "C:\\Users\\Joe User\\AppData\\Local\\Temp\\form-init11598934441516564808.clj", :name X, :ns #object[cl
(meta (var X)) ;; Here's the metadata for testing...
=>
{:line 1,
:column 1,
:file "C:\\Users\\Joe User\\AppData\\Local\\Temp\\form-init11598934441516564808.clj",
:name X,
:ns #object[clojure.lang.Namespace 0x12ed80f6 "thic.core"],
OneHundred 100,
NinetyNine 99}
我想删除entryeanetyine,剩下的元数据保持不变。
因此,我有一些代码可以工作:
它起作用了。第一百九十九条的条目已从X的元数据中删除
然后我把它编码成一个宏。上帝保佑雷普
(defmacro DelMeta! [S]
`(let [Hold# (meta (var ~S))] ;; Hold onto a copy of S's metadata.
(map ;; Scan through the copy looking for keys that DON'T start with ":"
(fn [[kee valu]]
(if ;; If we find metadata whose keyname does not start with a ":"
(not= \: (first (str kee)))
(reset-meta! (var ~S) (dissoc (meta (var ~S)) kee)) ;; remove it from S's metadata.
)
)
Hold# ;; Loop through the copy of S's metadata so as to not confuse things.
)
)
)
使用defmacro定义宏时不会出错。
宏上的macroexpand-1,例如
(macroexpand-1 '(DelMeta! X))
展开为正确的代码。在这里:
(macroexpand-1 '(DelMeta! X))
=>
(clojure.core/let
[Hold__2135__auto__ (clojure.core/meta (var X))]
(clojure.core/map
(clojure.core/fn
[[thic.core/kee thic.core/valu]]
(if
(clojure.core/not= \: (clojure.core/first (clojure.core/str thic.core/kee)))
(clojure.core/reset-meta! (var X) (clojure.core/dissoc (clojure.core/meta (var X)) thic.core/kee))))
Hold__2135__auto__))
但是
实际上,在REPL处使用实数参数调用宏会清除最不可理解的错误消息:
(DelMeta! X) ;;Invoke DelMeta! macro with symbol X.
Syntax error macroexpanding clojure.core/fn at (C:\Users\Joe User\AppData\Local\Temp\form-init11598934441516564808.clj:1:1).
([thic.core/kee thic.core/valu]) - failed: Extra input at: [:fn-tail :arity-1 :params] spec: :clojure.core.specs.alpha/param-list
(thic.core/kee thic.core/valu) - failed: Extra input at: [:fn-tail :arity-n :params] spec: :clojure.core.specs.alpha/param-list
哦,全能而智慧的克洛尤里戈兹,我恳求你的怜悯。
我的罪在哪里?这里不需要宏。此外,您还误解了Clojure关键字的性质,以及Clojure变量与局部变量的复杂性 通过在let块中使用局部变量而不是Var来保持简单:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(dotest
(let [x (with-meta [1 2 3] {:my "meta"})
x2 (vary-meta x assoc :your 25 'abc :def)
x3 (vary-meta x2 dissoc 'abc )]
(is= x [1 2 3])
(is= x2 [1 2 3])
(is= x3 [1 2 3])
(is= (meta x) {:my "meta"})
(is= (meta x2) {:my "meta", :your 25, 'abc :def})
(is= (meta x3) {:my "meta", :your 25}))
我们看到x,x2和x3的值是常数。这就是元数据的目的。第二组测试显示了使用vary meta对元数据的影响,这是更改值的最佳方式
当我们使用Var时,它不仅是一个全局值,而且就像C中指针的双间接寻址。请看这个问题:
这个答案还澄清了字符串、符号和关键字之间的区别。这很重要
考虑一下这个代码
(def ^{:my "meta"} data [1 2 3])
(spyx data)
(spyx-pretty (meta (var data)))
结果是:
data => [1 2 3]
(meta (var data)) =>
{:my "meta",
:line 19,
:column 5,
:file "tst/demo/core.cljc",
:name data,
:ns #object[clojure.lang.Namespace 0x4e4a2bb4 "tst.demo.core"]}
(is= data [1 2 3])
(is= (set (keys (meta (var data))))
#{:my :line :column :file :name :ns})
因此,我们根据需要将key:my添加到元数据中。我们怎样才能改变它?对于Var,使用函数alter meta
因此,我们向元数据映射添加了2个新条目。一个有关键字:your as key,值为25,另一个有符号abc as key,值为:def a关键字
我们也可以使用altermeta!要从元数据映射中远程密钥/val对,请执行以下操作:
(alter-meta! (var data) dissoc 'abc )
(is= (set (keys (meta (var data))))
#{:ns :name :file :your :column :line :my})
关键字vs符号vs字符串
源文件中的字符串文字在每一端都有双引号,但它们不是字符串中的字符。同样,源文件中的关键字文字也需要一个前导冒号来标识它。但是,字符串的双引号和关键字的冒号都不是该值名称的一部分
因此,您无法通过冒号识别关键字。您应该使用这些函数来标识不同的数据类型:
以上内容来自于。因此,您真正想要的代码是:
(defn remove-metadata-symbol-keys
[var-obj]
(assert (var? var-obj)) ; verify it is a Var
(doseq [k (keys (meta var-obj))]
(when (not (keyword? k))
(alter-meta! var-obj dissoc k))))
有一个样本:
(def ^{:some "stuff" 'other :things} myVar [1 2 3])
(newline) (spyx-pretty (meta (var myVar)))
(remove-metadata-symbol-keys (var myVar))
(newline) (spyx-pretty (meta (var myVar)))
结果:
(meta (var myVar)) =>
{:some "stuff",
other :things, ; *** to be removed ***
:line 42,
:column 5,
:file "tst/demo/core.cljc",
:name myVar,
:ns #object[clojure.lang.Namespace 0x9b9155f "tst.demo.core"]}
(meta (var myVar)) => ; *** after removing non-keyword keys ***
{:some "stuff",
:line 42,
:column 5,
:file "tst/demo/core.cljc",
:name myVar,
:ns #object[clojure.lang.Namespace 0x9b9155f "tst.demo.core"]}
以上代码都是使用运行的。这里不需要宏。此外,您还误解了Clojure关键字的性质,以及Clojure变量与局部变量的复杂性 通过在let块中使用局部变量而不是Var来保持简单:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(dotest
(let [x (with-meta [1 2 3] {:my "meta"})
x2 (vary-meta x assoc :your 25 'abc :def)
x3 (vary-meta x2 dissoc 'abc )]
(is= x [1 2 3])
(is= x2 [1 2 3])
(is= x3 [1 2 3])
(is= (meta x) {:my "meta"})
(is= (meta x2) {:my "meta", :your 25, 'abc :def})
(is= (meta x3) {:my "meta", :your 25}))
我们看到x,x2和x3的值是常数。这就是元数据的目的。第二组测试显示了使用vary meta对元数据的影响,这是更改值的最佳方式
当我们使用Var时,它不仅是一个全局值,而且就像C中指针的双间接寻址。请看这个问题:
这个答案还澄清了字符串、符号和关键字之间的区别。这很重要
考虑一下这个代码
(def ^{:my "meta"} data [1 2 3])
(spyx data)
(spyx-pretty (meta (var data)))
结果是:
data => [1 2 3]
(meta (var data)) =>
{:my "meta",
:line 19,
:column 5,
:file "tst/demo/core.cljc",
:name data,
:ns #object[clojure.lang.Namespace 0x4e4a2bb4 "tst.demo.core"]}
(is= data [1 2 3])
(is= (set (keys (meta (var data))))
#{:my :line :column :file :name :ns})
因此,我们根据需要将key:my添加到元数据中。我们怎样才能改变它?对于Var,使用函数alter meta
因此,我们向元数据映射添加了2个新条目。一个有关键字:your as key,值为25,另一个有符号abc as key,值为:def a关键字
我们也可以使用altermeta!要从元数据映射中远程密钥/val对,请执行以下操作:
(alter-meta! (var data) dissoc 'abc )
(is= (set (keys (meta (var data))))
#{:ns :name :file :your :column :line :my})
关键字vs符号vs字符串
源文件中的字符串文字在每一端都有双引号,但它们不是字符串中的字符。同样,源文件中的关键字文字也需要一个前导冒号来标识它。但是,字符串的双引号和关键字的冒号都不是该值名称的一部分
因此,您无法通过冒号识别关键字。您应该使用这些函数来标识不同的数据类型:
以上内容来自于。因此,您真正想要的代码是:
(defn remove-metadata-symbol-keys
[var-obj]
(assert (var? var-obj)) ; verify it is a Var
(doseq [k (keys (meta var-obj))]
(when (not (keyword? k))
(alter-meta! var-obj dissoc k))))
有一个样本:
(def ^{:some "stuff" 'other :things} myVar [1 2 3])
(newline) (spyx-pretty (meta (var myVar)))
(remove-metadata-symbol-keys (var myVar))
(newline) (spyx-pretty (meta (var myVar)))
结果:
(meta (var myVar)) =>
{:some "stuff",
other :things, ; *** to be removed ***
:line 42,
:column 5,
:file "tst/demo/core.cljc",
:name myVar,
:ns #object[clojure.lang.Namespace 0x9b9155f "tst.demo.core"]}
(meta (var myVar)) => ; *** after removing non-keyword keys ***
{:some "stuff",
:line 42,
:column 5,
:file "tst/demo/core.cljc",
:name myVar,
:ns #object[clojure.lang.Namespace 0x9b9155f "tst.demo.core"]}
上面的代码都是用运行的。我开始写答案,但停了下来,因为不清楚您到底想实现什么。一些提示:我没有得到相同的异常,相反,我得到一个异常,告诉我“kee”不存在——如果你想使用它,你想使用kee和valu。阅读变量捕获,例如在中。第二,当您想要的只是副作用时调用map,使用doseq可以更清楚地表示副作用。但主要的问题是,为什么您首先要使用非关键字元数据?这里的map是错误的,doseq也是错误的,因为两个更新会相互碰撞。在里面
不要使用reduce或into/for在功能上构建一个新的地图,然后设置一次。我发现结尾行非常有趣。hahaI开始写答案,但停了下来,因为不清楚你到底想实现什么。一些提示:我没有得到相同的异常,相反,我得到一个异常,告诉我“kee”不存在——如果你想使用它,你想使用kee和valu。阅读变量捕获,例如在中。第二,当您想要的只是副作用时调用map,使用doseq可以更清楚地表示副作用。但主要的问题是,为什么您首先要使用非关键字元数据?这里的map是错误的,doseq也是错误的,因为两个更新会相互碰撞。相反,使用reduce或into/for在功能上构建一个新的地图,然后设置一次。我发现结尾行非常有趣哈兰·汤普森:你以前回答过我的问题,我想我希望你在这里再次这样做。你做到了!600字!:非常感谢你。让我仔细检查一下,试一下你们的样品,然后再给你们回复。金星队,欧比万。读一下。几个月前,我花了一段时间摸索符号->变量->价值链。我经常想象Clojure在幕后使用某种双重间接手段。谢谢你的确认。我对Clojure的入门知识不包括“keys”函数或“keyword”函数。让我玩一下,我会回答更多的问题,或者希望不会艾伦·汤普森:你以前回答过我的问题,我想我希望你在这里再次这样做。你做到了!600字!:非常感谢你。让我仔细检查一下,试一下你们的样品,然后再给你们回复。金星队,欧比万。读一下。几个月前,我花了一段时间摸索符号->变量->价值链。我经常想象Clojure在幕后使用某种双重间接手段。谢谢你的确认。我对Clojure的入门知识不包括“keys”函数或“keyword”函数。让我玩一下,我会回答更多的问题,或者希望不会