Clojure fn支持get in的关键字或路径参数

Clojure fn支持get in的关键字或路径参数,clojure,keyword,Clojure,Keyword,Clojure中支持函数参数的干净方法是什么?函数参数可以是像:name这样的关键字,也可以是像[:person:name]这样的路径,以便可以在调用get或get in时使用 现在我有(进入m(展平[path])其中输入路径。这是可行的,但对于频繁使用,或者在大量数据收集中,它可能会变得缓慢——我还没有进行基准测试 或者,我想我可以在(coll?path)上调度以使用获取或获取: (let [path [:person :name] m {:person {:name "John

Clojure中支持函数参数的干净方法是什么?函数参数可以是像
:name
这样的关键字,也可以是像
[:person:name]
这样的路径,以便可以在调用
get
get in
时使用

现在我有
(进入m(展平[path])
其中输入
路径。这是可行的,但对于频繁使用,或者在大量数据收集中,它可能会变得缓慢——我还没有进行基准测试

或者,我想我可以在
(coll?path)
上调度以使用
获取
获取

(let [path [:person :name]
      m {:person {:name "John Smith"}}]
  (if (coll? path)
    (get-in m path) 
    (get m path)))
=> {:name "John Smith"}

这似乎更有效。

如果您确实需要调用方能够传入关键字或关键字序列,这是一种完全合法的方式。我可能会使用
关键字?
作为测试,而不是
coll?
,不过,为了让它更清楚一些
coll?
会给出一些误报(例如,当输入是一个映射而不是向量或序列时),但
关键字?
不会

(let [m {:person {:name "John Smith"}}]
      path [:person :name]
  (if (keyword? path)
    (get m path)
    (get-in m path)))
;=> "John Smith"
另一种方法是将输入视为简单的函数,这将允许您完全避免条件:

(let [m {:person {:name "John Smith"}}
      f (comp :name :person)]
  (f m))
;=> "John Smith"
但是,这并不像仅仅是关键字或关键字序列那么好,而且它允许调用者传入任意函数来访问映射可能会导致问题

不过,在这种情况下,最好的选择可能是强制用户按顺序传递,并始终使用
get-in
。这将避免这种条件映射的复杂性,并允许更一般的映射。考虑这个例子:

(let [m {[:foo :bar] "John Smith"
         :foo {:bar "John Cena"}}
      path [:foo :bar]]
  (if (coll? path)
    (get-in m path)
    (get m path)))
;=> "John Cena"

在这种情况下,
路径
完全不明确;根本无法确定打电话的人真正想要什么。如果地图中的所有键都是关键字,那就很好了;你不需要处理这个问题。但这正好说明,添加隐式转换可能会让你在以后开枪自杀。

关于模糊性的观点很好。另一种选择是支持korks,例如,
(my-fn:some:path)
,它被解析为
[&path]
,它支持
(my-fn[:foo:bar])
(my-fn:foo:bar)
@pate-Yep,如果您可以使用可变参数,请务必这样做。它基本上只是在序列中传递的语法糖,这就是为什么它在这里没有任何歧义的原因。它不同,因为你可以做
(我的fn[:foo:bar]:more:bar)
,这将导致
(进入m[:foo:bar]:more:bar])
,不?@pate术语“语法糖”在这种情况下并不正确;我为此道歉。我的意思是,一般来说,
((fn[args]args)[foo:bar]:baz:qux])
((fn[&args]args)[:foo:bar]:baz:qux)之间没有实际区别。无论哪种方式,你都可以毫不含糊地传递相同的东西;唯一的区别是调用代码的样子。