Clojure将函数列表应用于参数列表

时间:2018-07-11 14:11:01

标签: clojure

我有一个调整价格的功能列表和一个产品列表。 作为输出,我希望有相同的产品列表,但价格会调整。

从技术上讲,有功能列表和地图列表。 我想要实现的是将每个功能顺序应用到列表中的每个地图,同时保留初始结构

(def products
  [{:id 1 :price 100}
   {:id 2 :price 200}])

(defn change-price
  "increase by 10 => (change-price product 10 +)"
  [product amount price-func]
  (update product :price #(int (price-func amount %))))

(defn adjust-price
  [products]
  ;;fn-list is a list of price adjuster functions
  (let [fn-list [#(change-price % 10 +)
                 #(change-price % 50 -)]]
  ;; so I map a function to each product
  ;; which applies all adjsuter functions to that product
    (merge (map (fn [prod] 
        (map #(% prod) fn-list)) products)))

似乎我不明白如何适当地减少结果,因为我得到的是一个嵌套列表,例如

   (change-price products)
=> (({:id 1, :price 110} {:id 1, :price -50})
    ({:id 2, :price 210} {:id 2, :price -150}))

但是我希望

({:id 1, :price 60} {:id 2, :price 160})

谢谢。

3 个答案:

答案 0 :(得分:2)

似乎您想应用功能的组合:

(defn adjust-price
  [products]
  (let [fn-list [#(change-price % 10 +)
                 #(change-price % 50 -)]
        f (apply comp fn-list)]
    (map f products)))

答案 1 :(得分:1)

事情是map不会“挤压”结果:它只是使list [n] => list [n]。

您需要的是reduce,如下所示:

user> (let [fn-list [#(change-price % 10 +)
                     #(change-price % 50 -)]]
        (map (fn [p] (reduce #(%2 %1) p fn-list))
             products))

;;=> ({:id 1, :price -60} {:id 2, :price -160})

您还必须重写您的change-price函数,因为这里的参数数目错误:(price-func amount %) => (price-func % amount)

答案 2 :(得分:1)

您不会改变传入的哈希图,因此当您按照您的方式在一个项目上调用两个不同的函数时,您将获得不同的结果。

在“调整价格”函数中,由于您正在使用“地图”来执行“更改价格”函数,因此您当前是说,运行第一个更改价格函数一次,返回一个值,然后运行第二个价格函数一次,返回一个单独的值,导致: ({:id 1, :price 110} {:id 1, :price -50})

上面的答案很好,只是想我会使用线程函数添加另一种方法来做到这一点,这样您就不必担心顺序了。

(defn adjust-price
  [products]
  (let [f #(-> % 
               (change-price 10 +)
               (change-price 50 -))]
    (map f products)))

记住,单线程'->'表示你将当前行(函数)的结果向下传递到下一行(函数),并将用作第一个参数

(ps。我知道这是一个旧帖子,但希望这能帮助其他人:)