Clojure应用地图和关键字参数销毁

Zau*_*bov 13 clojure map destruction keyword-argument

考虑具有以下签名的函数:

(defn make-widget [& {:keys [x y] :or {x 10 y 20}}]
 ...)
Run Code Online (Sandbox Code Playgroud)

将地图传递给函数的最佳方法是什么,例如:

(make-widget {:x 100})
Run Code Online (Sandbox Code Playgroud)

要么

(make-widget {:y 200 :x 0})
Run Code Online (Sandbox Code Playgroud)

目前有什么我想到的是通过vec,flattenapply如:

(apply make-widget (flatten (vec ({:x 100}))
Run Code Online (Sandbox Code Playgroud)

我坚信有更好的方法可以做到这一点.你能考虑一下吗?

Rör*_*örd 11

我想不出更优雅的方式,尽管在我看来应该有一个(比如地图特定的变体apply).

flatten然而,使用有一些问题,而不是非常优雅.如果你的地图的价值是集合,那么它们flatten也会以递归方式工作,所以事情可能完全混淆了.这个替代方案避免了这个问题:

(apply make-widget (apply concat {:x 100}))
Run Code Online (Sandbox Code Playgroud)


non*_*com 8

还有一个已知的(至少不是我发明的),功能"mapply":

(defn mapply [f & args] (apply f (apply concat (butlast args) (last args))))
Run Code Online (Sandbox Code Playgroud)

哪个可以应用

(mapply your-function {:your "map"})
Run Code Online (Sandbox Code Playgroud)

至于为什么Clojure核心缺少这种特定于语言的功能,更加原生和优雅地实现,没有人能给我一个明确的答案.

UPDATE

在Clojure上花了很多时间编程后,我个人倾向于避免创建接受{}一个vararg的函数.虽然起初这看起来很吸引人,但实际上经验证明,{}由于许多原因,传递明确总是更好.


Ank*_*kur 7

您可以使用:

(apply make-widget (mapcat identity {:x 200 :y 0}))
Run Code Online (Sandbox Code Playgroud)