2024 年 Clojure 状态调查 中分享您的想法!

欢迎!请查看 关于 页面以获取有关如何进行操作的更多信息。

0

我在尝试做《Brave Clojure》第8章的练习(第3题)。我已经简化了它以找到问题所在。

考虑以下设置

(def person {:first-name "Louis"
             :last-name "Bourvil"
             :age 32
             :city "Nantes"})

我想做到以下几点

(create-func c-age :age)
(c-age person)

我知道这个是有效的

(defmacro create-func [func-name attr] `(def ~func-name ~attr))

但我尝试使用一个函数来做,却不知道为什么这个不生效

(defmacro create-func [func-name attr] `(defn ~func-name [person] (~attr person)))
(create-func c-age :age)
; Syntax error macroexpanding clojure.core/defn at (REPL:1:1).
; user/person - failed: vector? at: [:fn-tail :arity-n :bodies :params] spec: 
:clojure.core.specs.alpha/param-list
; (user/person) - failed: Extra input at: [:fn-tail :arity-1 :params] spec: 
:clojure.core.specs.alpha/param-list

(从 repl 获得)

你能看出我的错误在哪里吗?

1 个答案

0

被选中
 
最佳答案
(defmacro create-func [func-name attr] `(defn ~func-name [person] (~attr person)))
(create-func c-age :age)

当你这样写时,它将会展开为

(defn c-age [user/person] (:age user/person))
Syntax error macroexpanding clojure.core/defn at (/tmp/form-init14482279258588584188.clj:1:1).
user/person - failed: vector? at: [:fn-tail :arity-n :bodies :params] spec: :clojure.core.specs.alpha/param-list
(user/person) - failed: Extra input at: [:fn-tail :arity-1 :params] spec: :clojure.core.specs.alpha/param-list

为了避免这一点,你应该这样写

(defmacro create-func [func-name attr] `(defn ~func-name [person#] (~attr person#)))

或者使用其他方式在参数名称中不使用限定符号。

在 Clojure 中,“getter”宏定义是一个反模式。
如果你想要访问一个字段,就直接访问它。
此外,通常 def-macros 可以写成一个函数

(def c-age (im-not-a-macro :age))
非常感谢!这只是一次Brave clojure的练习...
欢迎来到Clojure问答社区,在这里您可以提问并从Clojure社区的成员那里获得答案。
...