Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure Partial Application - How to get 'map' to return a collection of functions?

I have a function that I basically yanked from a discussion in the Clojure google group, that takes a collection and a list of functions of arbitrary length, and filters it to return a new collection containing all elements of the original list for which at least one of the functions evaluates to true:

(defn multi-any-filter [coll & funcs]
    (filter #(some true? ((apply juxt funcs) %)) coll))

I'm playing around with making a generalizable solution to Project Euler Problem 1, so I'm using it like this:

(def f3 (fn [x] (= 0 (mod x 3))))
(def f5 (fn [x] (= 0 (mod x 5))))

(reduce + (multi-any-filter (range 1 1000) f3 f5))

Which gives the correct answer.

However, I want to modify it so I can pass ints to it instead of functions, like

(reduce + (multi-any-filter (range 1 1000) 3 5))

where I can replace 3 and 5 with an arbitrary number of ints and do the function wrapping of (=0 (mod x y)) as an anonymous function inside the multi-any-filter function.

Unfortunately this is past the limit of my Clojure ability. I'm thinking that I would need to do something with map to the list of args, but I'm not sure how to get map to return a list of functions, each of which is waiting for another argument. Clojure doesn't seem to support currying the way I learned how to do it in other functional languages. Perhaps I need to use partial in the right spot, but I'm not quite sure how.

In other words, I want to be able to pass an arbitrary number of arguments (that are not functions) and then have each of those arguments get wrapped in the same function, and then that list of functions gets passed to juxt in place of funcs in my multi-any-filter function above.

Thanks for any tips!

like image 971
Alex Kyllo Avatar asked Mar 14 '13 19:03

Alex Kyllo


1 Answers

(defn evenly-divisible? [x y]
  (zero? (mod x y)))

(defn multi-any-filter [col & nums]
  (let [partials (map #(fn [x] (evenly-divisible? x %)) nums)
        f (apply juxt partials)]
    (filter #(some true? (f %)) col)))

I coudn't use partial because it applies the arg in the first position of the fn. We want it in the second position of evenly-divisible? We could re-arrange in evenly-divisible? but then it would not really look correct when using it standalone.

user=> (reduce + (multi-any-filter (range 1 1000) 3 5))
233168
like image 94
Kyle Avatar answered Sep 19 '22 08:09

Kyle