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#)))

或者使用另一种不使用有资格的符号作为参数名的方法。

为 "getter" 创建宏是 clojure 中的一个反模式。
如果你想访问一个字段,只需访问它。
此外,def-macros 通常可以写成函数的形式。

(def c-age (im-not-a-macro :age))
非常感谢!这是一道来自Brave clojure的练习...
...