首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >计算传递给Clojure中def的符号。

计算传递给Clojure中def的符号。
EN

Stack Overflow用户
提问于 2017-02-23 15:45:06
回答 2查看 609关注 0票数 1

我正在为勇敢和真而努力。在关于宏的一章中,有这样的练习:

编写一个宏,该宏使用一个宏调用定义任意数量的属性检索函数。你可以这样称呼它:

代码语言:javascript
复制
(defattrs c-int :intelligence
          c-str :strength
          c-dex :dexterity)

这些函数所做的是从映射中检索值。例如:给定:(def character {:name "Travis", :intelligence 20, :strength 23, :dexterity 13})

(c-int character)的结果是20,当然,这样的函数可以很容易地定义为(def c-int #(:intelligence %))

这就是我想出的解决问题的方法:

代码语言:javascript
复制
(defmacro defattrs
    [& attributes]
    `(let [attribute-pairs# (partition 2 (quote ~attributes))]
          (map (fn [[function-name# attribute-key#]]
                   (def function-name# #(attribute-key# %)))
           attribute-pairs#)))

我遇到的问题是,def使用生成的符号名,而不是它决定定义函数的内容(事后看来,考虑到def的使用,这是有意义的)。我尝试在定义函数时使用表达式,例如:

代码语言:javascript
复制
(let [x ['c-int :intelligence]]
  (def (first x) #((second x) %)))

已导致此错误:CompilerException java.lang.RuntimeException: First argument to def must be a Symbol, compiling:(/tmp/form-init5664727540242288850.clj:2:1)

对我如何做到这一点有什么想法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-02-23 18:54:17

对于不需要以表单形式生成的attributes参数,有一些常见的操作:

  • 将属性拆分为属性对;以及
  • 定义函数,为每对生成一个def表单。

把上面的代码应用到你的代码中,我们得到.

代码语言:javascript
复制
(defmacro defattrs [& attributes]
  (let [attribute-pairs (partition 2 attributes)]
     (map (fn [[function-name attribute-key]]
            `(def ~function-name #(~attribute-key %)))
          attribute-pairs)))
  • 反向报价的范围仅限于我们希望生成的def
  • 函数的function-nameattribute-key参数的值被插入到def表单中。

还有一个问题。

  • map的结果是一个def表单序列。
  • 第一个函数将被解释为应用于其余部分的函数。

解决方案是将一个cons do放在序列的前面:

代码语言:javascript
复制
(defmacro defattrs [& attributes]
  (let [attribute-pairs (partition 2 attributes)]
    (cons 'do
          (map (fn [[function-name attribute-key]]
                 `(def ~function-name ~attribute-key))
               attribute-pairs))))

我还在后面引用的表单中将#(~attribute-key %)缩写为等效的~attribute-key

让我们看看扩展是什么样子的:

代码语言:javascript
复制
(macroexpand-1 '(defattrs dooby :brrr))
;(do (def dooby :brrr))

看起来不错。我们试试看!

代码语言:javascript
复制
(defattrs gosh :brrr)
(gosh {:brrr 777})
;777

它起作用了。

票数 2
EN

Stack Overflow用户

发布于 2017-02-23 16:48:35

你已经找到了回溯和倾斜的用例。试试看:

代码语言:javascript
复制
(let [x ['c-int :intelligence]]
  (eval `(def ~(first x) #(~(second x) %))))

(def character {:name "Travis", :intelligence 20, :strength 23, :dexterity 13})

(c-int character) => 20

后引号类似于单引号,因为它将下一个格式变成列表、符号等的数据结构。不同的是,数据结构被用作模板,其中内部位可以用倾斜体替换。最酷的部分是,tilde不仅可以替代项,而且可以用于任何任意Clojure表达式的活动代码。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42420250

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档