【发布时间】:2018-06-26 03:14:13
【问题描述】:
假设我有几个向量
(def coll-a [{:name "foo"} ...])
(def coll-b [{:name "foo"} ...])
(def coll-c [{:name "foo"} ...])
我想看看第一个元素的名称是否相等。
我可以
(= (:name (first coll-a)) (:name (first coll-b)) (:name (first coll-c)))
但是随着更多函数的组合,这很快就会变得很累并且过于冗长。 (也许我想比较第一个元素名称的最后一个字母?)
要直接表达计算的本质,似乎很直观
(apply = (map (comp :name first) [coll-a coll-b coll-c]))
但这让我想知道这种事情是否有更高级别的抽象。
我经常发现自己比较/以其他方式操作要通过应用于多个元素的单个组合来计算的事物,但映射语法对我来说有点不妥。
如果我要自制某种运算符,我会想要这样的语法
(-op- (= :name first) coll-a coll-b coll-c)
因为大部分计算都以(= :name first) 表示。
我想要一个抽象应用于运算符和应用于每个参数的函数。也就是说,求和应该和比较一样容易。
(def coll-a [{:name "foo" :age 43}])
(def coll-b [{:name "foo" :age 35}])
(def coll-c [{:name "foo" :age 28}])
(-op- (+ :age first) coll-a coll-b coll-c)
; => 106
(-op- (= :name first) coll-a coll-b coll-c)
; => true
类似
(defmacro -op-
[[op & to-comp] & args]
(let [args' (map (fn [a] `((comp ~@to-comp) ~a)) args)]
`(~op ~@args')))
- 在 clojure 中是否有一种惯用的方式来执行此操作,我可以使用一些标准库函数?
- 这种表达式有名称吗?
【问题讨论】:
-
编写宏是通常是惯用的方式,前提是使用标准函数不可能。如果你想要这样的语法,你几乎不得不使用宏,这基本上是在创建一个 DSL,这不一定是坏事。
-
不,这里绝对不需要宏,除非你在真的不需要宏时一心想创建一个 DSL。
标签: clojure functional-programming operators higher-order-functions