在Clojure中使用函数列表构建映射
我对Clojure还比较陌生,所以我在思考如何做以下工作时遇到了困难 从一个Java方法(来自reflect包)开始,我想提取各种属性,最后得到一个如下所示的映射:在Clojure中使用函数列表构建映射,clojure,Clojure,我对Clojure还比较陌生,所以我在思考如何做以下工作时遇到了困难 从一个Java方法(来自reflect包)开始,我想提取各种属性,最后得到一个如下所示的映射: { :name "test-method :return-type "String" :public true } 由于构建键的逻辑可能相当复杂,我想链接一系列函数,这些函数接受当前映射和方法对象,并修改映射或按原样返回。比如: (defn build-public [acc method] (if (is-publi
{ :name "test-method
:return-type "String"
:public true
}
由于构建键的逻辑可能相当复杂,我想链接一系列函数,这些函数接受当前映射和方法对象,并修改映射或按原样返回。比如:
(defn build-public
[acc method]
(if (is-public? method) (assoc acc :public true) acc))
这可以称为:
(make-method-map method [build-public build-return-type build-name])
我尝试过几种不同的方法,但似乎无法奏效,任何建议都将不胜感激。一种方法是使用
cond->
,它结合了cond
和->
的概念
(cond-> {:my-map 1}
(= 2 2) (assoc :two-equals-two true)
(= true false) (assoc :not-possible "hey"))
=> {:my-map 1, :two-equals-two true}
左侧的子句决定是否对右侧的表单求值,初始值在第一个位置穿行。简单的方法是使用reduce:
user> (defn make-method-map [method fns]
(reduce (fn [acc f] (f acc method))
{} fns))
#'user/make-method-map-2
user> (defn make-name [acc method]
(assoc acc :name 123))
#'user/make-name
user> (defn make-other [acc method]
(assoc acc :something "ok"))
#'user/make-other
user> (make-method-map {:a 1 :b 2} [make-name make-other])
;;=> {:name 123, :something "ok"}
我会这样写
makemethodmap
:
(defn method-map [method]
(-> {}
(assoc :return-type (get-return-type method))
(assoc :name (get-name method))
(cond-> (public? method) (assoc :public? true))))
(defn method-map [method]
(-> {}
(assoc :return-type (get-return-type method))
(assoc :name (get-name method))
(assoc :public? (public? method))))
请注意如何将cond->
(或as->
或->
)嵌套在->
中。但是,将它们中的任何一个放在->
或类似文件中可能并不像您预期的那样有效
这是为什么留给读者作为练习
实际上我会这样写:
(defn method-map [method]
(-> {}
(assoc :return-type (get-return-type method))
(assoc :name (get-name method))
(cond-> (public? method) (assoc :public? true))))
(defn method-map [method]
(-> {}
(assoc :return-type (get-return-type method))
(assoc :name (get-name method))
(assoc :public? (public? method))))
或者,如果我能侥幸逃脱的话,可以使用文字映射(一步不取决于下一步,等等)
但这并没有显示嵌套cond->
的技巧
(cond-> {:my-map 1}
(= 2 2) (assoc :two-equals-two true)
(= true false) (assoc :not-possible "hey"))
=> {:my-map 1, :two-equals-two true}
如果你发现自己有一个函数向量,那么leetwinski的答案是好的。就像编程中的每一件事一样,这要视情况而定
编辑:
对于正在使用的函数向量的真实示例,请查看或中的拦截器概念。我喜欢
reduce fns
选项,但这里有一个具有稍微不同的函数签名的替代方案:
(defn make-name [method] {:name (str (:a method) "-" (:b method))})
(defn make-other [method] {:a-is-3 (= (:a method) 3)})
(defn make-method-map [method fns]
(into {} ((apply juxt fns) method)))
(defn make-method-map [method fns]
(reduce merge ((apply juxt fns) method)))
(defn make-method-map [method fns]
(apply merge ((apply juxt fns) method)))
(make-method-map {:a 1 :b 2} [make-name make-other])
; {:name "1-2", :a-is-3 false}
返回函数返回值的向量,此处不将
acc
作为输入参数,而是将转换为或reduce
用于将这些哈希映射“合并”到最终结果中。最初我想使用comp
,但是这些函数的样式没有那么“可组合”。嵌套线程宏的事情解释得很好。这真的很棒。我一直在挖掘康德更多,真的很棒的工具!我最终实现了这个解决方案。它一直工作得很好。谢谢