在Clojure中,如果我有一个功能 F,
(defn f [& r] ... )
我有一个seq ARGS 有了我想要调用f的参数,我可以轻松使用 应用:
(apply f args)
现在,说我有另一个功能 G,它被设计为采用任意一些可选的命名参数 - 也就是说,其余参数被解构为一个映射:
(defn g [& {:keys [a b] :as m}] ... )
我通常会做类似的事情
(g :a 1 :b 2)
但如果我碰巧有地图 我的地图 值{:a 1:b 2},我想“将”g“应用”到我的地图 - 换句话说,得到一些最终会成为上述调用的东西,然后我自然不能使用apply,因为它等同于
(g [:a 1] [:b 2])
有一个很好的方法来处理这个?我可以在设计中偏离轨道以达到目的吗?我能找到的最佳解决方案是
(apply g (flatten (seq my-map)))
但我肯定不喜欢它。更好的解决方案?
编辑: 建议的解决方案略有改进
(apply g (mapcat seq my-map))
至少删除了一个函数调用,但它可能仍然不是很清楚正在发生什么。
我自己偶然发现了这个问题,最后定义了一个期望一个地图的函数。映射可以具有可变数量的键/值对,并且如果足够灵活,则不需要&rest参数。申请也没有痛苦。让生活更轻松!
(defn g [{:keys [a b] :as m}] ... )
我自己偶然发现了这个问题,最后定义了一个期望一个地图的函数。映射可以具有可变数量的键/值对,并且如果足够灵活,则不需要&rest参数。申请也没有痛苦。让生活更轻松!
(defn g [{:keys [a b] :as m}] ... )
没有比转换为seq更好的直接方式。
你完成了。你已尽力而为。
使用Common Lisp风格并不是真正的烦恼:关键字arg函数。如果你环顾Clojure代码,你会发现几乎没有任何函数以这种方式编写。
即使是伟大的RMS也不是他们的粉丝:
“我不太喜欢的一件事是关键词参数(8)。它们对我来说似乎并不太可能;我有时会这样做,但我最小化了这样做的时间。” (资源)
在您必须将完整的哈希映射分解为片段以将所有这些作为关键字映射参数传递的时刻,您应该质疑您的函数设计。
我发现在你要传递一般选项的情况下 :consider-nil true
您可能永远不会使用哈希映射调用该函数 {:consider-nil true}
。
在您想要根据哈希映射的某些键进行评估的情况下,您有99%的时间都有 f ([m & args])
宣言。
当我开始在Clojure中定义函数时,我遇到了同样的问题。但是在仔细考虑了我试图解决的问题之后,我注意到自己在函数声明中几乎从不使用析构函数。
这是一个非常简单的函数,可以完全用作apply,除了最终的arg(应该是一个map)将扩展为:key1 val1:key2 val2等。
(defn mapply
[f & args]
(apply f (reduce concat (butlast args) (last args))))
我确信有更有效的方法可以做到这一点,并且你是否想要在你必须使用这样一个功能的情况下结束辩论,但它确实回答了原来的问题。大多数情况下,我对孩子的名字感到满足......
我发现最好的解决方案:
(apply g (apply concat my-map))