gpt4 book ai didi

macros - 没有括号的反引号

转载 作者:行者123 更新时间:2023-12-01 14:41:29 24 4
gpt4 key购买 nike

我正在阅读一本很棒的书 Let Over Lambda,我正在尝试将 defunits 的 Common Lisp 代码移植到 Clojure。

下面生成一个宏,它应该采用

(defn defunits-chaining [u units prev]
(if (some #(= u %) prev)
(throw (Throwable. (str u " depends on " prev))))
(let [spec (first (filter #(= u (first %)) units))]
(if (nil? spec)
(throw (Throwable. (str "unknown unit " u)))
(let [chain (second spec)]
(if (list? chain)
(* (first chain)
(defunits-chaining
(second chain)
units
(cons u prev)))
chain)))))

(defmacro defunits [quantity base-unit & units]
`(defmacro ~(symbol (str "unit-of-" quantity))
[valu# un#]
`(* ~valu#
~(case un#
~base-unit 1
~@(map (fn [x]
`(~(first x) ;; <-- PRETTY SURE IT'S THIS `(
~(defunits-chaining
(first x)
(cons `(~base-unit 1)
(partition 2 units))
nil)))
(partition 2 units))))))

(defunits time s m 60 h 3600)

并把它变成一个可以调用的宏

(unit-of-time 4 h)

并以基本单位(本例中为秒)给出结果。我认为问题是“案例”中的 Clojure/CL api 更改。 CL 中的“案例”如下所示:

(case 'a (('b) 'no) (('c) 'nope) (('a) 'yes))

但是在 Clojure 中...

(case 'a 'b 'no 'c 'nope 'a 'yes)

多么方便。我在嵌套的 defmacro 中更改了我的 anon 函数,但它一直像

(case un#
s 1
(m 60)
(h 3600)

我怎样才能防止这些外括号?

最佳答案

如果您将 map 包裹成扁平状,它应该会产生您要查找的结果。

(defmacro defunits [quantity base-unit & units]
`(defmacro ~(symbol (str "unit-of-" quantity))
[valu# un#]
`(* ~valu#
~(case un#
~base-unit 1
~@(flatten ;; <- changed this
(map (fn [x]
`(~(first x)
~(defunits-chaining
(first x)
(cons `(~base-unit 1)
(partition 2 units))
nil)))
(partition 2 units)))))))

发生了什么:在您的初始实现中,当您需要的是原子列表时,您的 map 返回的是列表列表。 Flatten获取任意深度的列表列表并将其转换为单个值列表。

另一种方法是使用 reduce而不是 map :

(defmacro defunits [quantity base-unit & units]
`(defmacro ~(symbol (str "my-unit-of-" quantity))
[valu# un#]
`(* ~valu#
~(case un#
~base-unit 1
~@(reduce (fn [x y] ;; <- reduce instead of map
(concat x ;; <- use concat to string the values together
`(~(first y)
~(defunits-chaining
(first y)
(cons `(~base-unit 1)
(partition 2 units))
nil))))
'()
(partition 2 units))))))

这将避免首先创建列表的列表,因为 reduce 会将所有传入的值汇总到一个结果中。

更好的是,(感谢 amalloy 发现了这个),还有 mapcat :

(defmacro defunits [quantity base-unit & units]
`(defmacro ~(symbol (str "unit-of-" quantity))
[valu# un#]
`(* ~valu#
~(case un#
~base-unit 1
~@(mapcat (fn [x] ;; <----- mapcat instead of map is the only change
`(~(first x)
~(defunits-chaining
(first x)
(cons `(~base-unit 1)
(partition 2 units))
nil)))
(partition 2 units))))))

Mapcat 有效地做了与 reduce 版本相同的事情,但隐式地为您处理了 concat。

关于macros - 没有括号的反引号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16350012/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com