Reputation: 47431
I have been coming across this pattern a lot in my code (map #(% a) fns)
where a is a variable say a string and fns is a seq of fns like [count #(split ",")]
. Is there a more concise way to express this pattern ?
Upvotes: 3
Views: 154
Reputation: 877
I think the thrush operators are called for here.
user=> (-> "a b c d"
.toUpperCase
(.replace "A" "X")
(.split " ")
first)
"X"
http://clojuredocs.org/clojure_core/clojure.core/-%3E
http://clojuredocs.org/clojure_core/clojure.core/-%3E%3E
Upvotes: 0
Reputation: 33657
The pattern is already concise. But if you want to create an abstraction which represent a function collection
and is also callable, you can try something like this:
(defmacro function-coll [param-count]
(let [params (repeatedly param-count gensym)
name (symbol (str "Functions-" param-count))]
`(deftype ~name [fns#]
clojure.lang.IFn
(invoke [_ ~@params] (map #(% ~@params) fns#)))))
(function-coll 1)
(def one-fns (->Functions-1 [inc dec]))
(one-fns 10)
(function-coll 2)
(def two-fns (->Functions-2 [str vector]))
(two-fns :hello :world)
Upvotes: 0
Reputation: 45131
A straightforward way to express it: (for [f fns] (f a))
Added only for completeness, it's as good as the map
-based expression, unless you like for
more than anonymous functions.
Upvotes: 1
Reputation: 26446
More concise? Probably not. Better idiom? Depends. juxt
will take any number of fns as arguments and provide a function that is their juxtaposition. So, you could use it in place of your map
like so
(def a "foo,bar,baz")
(map #(% a) [count #(split % #",")])
;=> (11 ["foo" "bar" "baz"])
((juxt count #(split % #",")) a)
;=> [11 ["foo" "bar" "baz"]]
On one hand, you have a lazy sequence of applications, on the other you have functional composition. Which is better depends on the need.
Upvotes: 3