Clojure中使用reduce结合partial调用多参数函数失败问题排查
问题描述
我定义了一个返回update-in结果的函数:
(defn abc [a fruit-1 fruit-2] (update-in a ["apples" (xyz fruit-1)] add-apple fruit-1 fruit-2))
由于该函数有3个参数,我尝试使用reduce结合partial来调用它:
(let [fruits (get-fruits config)] (let [the-basket (reduce (partial abc empty-map) (first fruits) (second fruits))] (if (empty? (the-basket "apples")) (throw (ex-info "Couldn't find" {})) the-basket)))
其中fruits包含两个元素,但调试发现abc函数并未被调用,且the-basket的值与(first fruits)完全相同。显然我使用reduce与partial的方式有误,请问这种调用三参数函数的方式是否正确?或者有更优的实现方式?
错误分析与解决方案
你的reduce用法不符合Clojure的规则:reduce要求传入的函数必须是接受两个参数的——第一个是累计结果(前一次调用的返回值),第二个是当前遍历的集合元素。而你当前的调用逻辑完全错位了:
(partial abc empty-map)生成的是一个需要两个参数的函数,但你把(first fruits)作为reduce的初始值,(second fruits)作为遍历集合,这既不符合abc的参数需求,也不符合reduce的调用结构。
场景1:fruits的两个元素是列表,需要逐个配对更新
如果fruits的结构是[fruit-1-list fruit-2-list],且两个列表长度一致,要逐个取对应位置的fruit-1和fruit-2来更新篮子,正确写法是先配对元素再reduce:
(let [fruits (get-fruits config) ; 把两个列表的元素一一配对成二元组 fruit-pairs (map vector (first fruits) (second fruits)) ; 用reduce累计更新,每次传入当前篮子和一对水果 the-basket (reduce (fn [acc [f1 f2]] (abc acc f1 f2)) empty-map fruit-pairs)] (if (empty? (the-basket "apples")) (throw (ex-info "Couldn't find" {})) the-basket))
也可以用更简洁的写法简化累计函数:
(reduce #(apply abc %1 %2) empty-map fruit-pairs)
场景2:fruits的两个元素是单个值
如果fruits只是包含两个单独的fruit-1和fruit-2,那根本不需要reduce,直接调用abc即可:
(let [[f1 f2] (get-fruits config) the-basket (abc empty-map f1 f2)] (if (empty? (the-basket "apples")) (throw (ex-info "Couldn't find" {})) the-basket))
内容的提问来源于stack exchange,提问作者stuck
相关产品推荐
相关产品推荐

