Map 存储分解映射以供以后使用
我一直在努力让这项工作与报价,报价拼接,评估,以及任何其他我能想到的,但没有运气到目前为止。我理解为什么它不起作用——它被视为一张地图,它试图评估Map 存储分解映射以供以后使用,map,clojure,destructuring,Map,Clojure,Destructuring,我一直在努力让这项工作与报价,报价拼接,评估,以及任何其他我能想到的,但没有运气到目前为止。我理解为什么它不起作用——它被视为一张地图,它试图评估a、b、和c——而不是如何绕过它 (def destructor {a :a b :b c :c}) ; CompilerException java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(:1:15) (let [destruct
a
、b
、和c
——而不是如何绕过它
(def destructor {a :a b :b c :c})
; CompilerException java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(:1:15)
(let [destructor my-map]
'etc)
我有一个相当复杂的分解图,我正在考虑使用几次,所以把它藏在某个地方似乎是个好主意。也许有更好的方法可以实现这一点?好主意,但你不能完全用这种方法来实现,因为你想要存储的东西实际上不是一个值,所以你不能将它存储在变量中 相反,您可以定义一个宏,在其展开中包含以下内容:
(defmacro with-abc [abc & body]
`(let [~'{:keys [a b c]} ~abc]
~@body))
(with-abc foo
(...use a, b, and c...))
类似于@amalloy的回答也是我的第一直觉,这可能是我的方向。也就是说,可能值得考虑一个普通的高阶函数:
(defn destruct
[{a :a b :b c :c} f]
(f a b c))
(destruct my-map
(fn [a b c]
(println a)
(println b)
(println c)))
它有点刺耳,您每次都必须命名绑定,但您可以避免潜在的卫生问题,并且根据元编程的舒适程度,它更容易组合起来。您需要引用破坏模式
(def my-destructor '{a :a b :b c :c})
您可以使用引号/取消引号级别来实现这一点,但是使用一个小的辅助函数更容易看到
(defn- with-destructor* [binding & body]
`(let ~binding ~@body))
此eval
发生在“编译”时(在宏扩展期间)
如图所示
(macroexpand-1 '(with-destructor [my-destructor {:a 1 :c 3}] (+ a c)))
;=> (clojure.core/let [{a :a, b :b, c :c} {:a 1, :c 3}] (+ a c))
结果
(with-destructor [my-destructor {:a 1 :c 3}] (+ a c))
;=> 4
let子句中看起来很滑稽的
~'
是这样的:a、b和c不会得到语法引号限定的名称空间。我认为这是必要的,但我现在不是在一台真正的电脑前,所以如果有人看到它,你就不能随意编辑。非常好。我不能使用:keys
(不过很高兴将其视为一个示例),因为我有一个“相当复杂的分解图”(即多个级别),但在我的图中交换效果非常好。我曾经尝试过使用宏,但是——尽管已经成功地使用了很多次——我想我还没有完全意识到将所有的东西都传递进来,并得到一个全新的、完全改变的东西。谢谢@阿马洛伊:说实话,你是对的,~”
是必要的。我对它进行了测试,它可以正常工作,但是去掉~”
会导致java.lang.RuntimeException:不能让限定名:user/a
。是的,我想避免命名东西,因为我的地图不仅包含几十个东西,而且它们还处于几个不同的嵌套级别。不过,在可能的情况下,尝试找到功能性路线是很好的。谢谢,明白了。听起来宏就是这样。带析构函数的的定义根本没有理由使用eval
。它的主体应该是(与析构函数一起应用*[destructor form]body)
。当然,如果你用析构函数*
从中删除vararg,你可以避免应用
。@amalloy也许我遗漏了什么,但我相信你的建议只适用于中的字面析构函数表达式(用析构函数[{a:ab:bc:c}{a 1:c3})(+ac))
,但是没有一个像问题中那样存储在var中,我明白了。您试图让用户提供析构函数
,而不是修复特定宏。我很困惑,因为您将宏参数命名为与var相同的参数,并且我认为宏是指var。
(with-destructor [my-destructor {:a 1 :c 3}] (+ a c))
;=> 4