你好,我有一个像这样的简单函数:
(def state
(memoize
(fn state [t]
(if (<= t 0)
0
1))))
我试图调用(reduce state (range 10))
,其意图是在state
范围内调用函数0 1 2 3 4 5 ...
,并接收回0 1 1 1 1 1 1 1 1 1
。
这种情况没有发生,因此我显然误解了一些事情,因为我得到了:
clojure.lang.ArityException: Wrong number of args (2) passed to: state
reduce的语法是(reduce f coll)
,我的理解是它就像执行(reduce + [1 2 3 4 5])
一样简单。
显然,人们可以使用map
轻松完成此操作。我只是认为reduce
也会起作用。使用地图(map (fn [x] (state x)) (range 10))
。
PS。这只是一个测试用例,我真的需要memoization
才能获得真实的东西。
由于
答案 0 :(得分:3)
显然,人们可以很容易地使用地图做到这一点我只是觉得减少也会起作用。
是。任何map
也可以是reduce
。 (除了减少不是懒惰,而地图是)。
reduce函数的结果将是在函数N次迭代超过缩小范围后最终返回的结果。
您的函数返回0或1,因此,您的reduce最终将返回0或1。
如果要返回列表,则缩减功能需要返回列表。或者,使用除reduce之外的函数,例如map。
此外 - 所有减少函数都需要2个参数,而不是1.因此,state
函数不是传递给reduce的有效函数。但是,传递给地图是一个有效的功能。
顺便提一下,你可以通过reduce来实现这一点,你不需要 map - 事实上,许多函数可以表示为reduce,包括map,过滤器等。但是,您需要更改缩小功能以使其兼容。
评论和其他答案表明你必须使用地图,但这里有一个减少:
(def state
(memoize
(fn state [r t]
(if (<= t 0)
(conj r 0)
(conj r 1)))))
(reduce state [] (range 10))
;;-> [0 1 1 1 1 1 1 1 1 1]
如果您具有依赖于了解其他项目的特定项目的值的逻辑,那么这是一个很好的习惯用法。你在这里没有这样的逻辑,所以map是更好的选择。但从概念上讲,你可以用fold
来表达函数式编程中的很多东西,这就是reduce
。
这是另一种方法,保留问题中的原始state
函数,因此其记忆完好无损:
(def state
(memoize
(fn state [t]
(if (<= t 0)
0
1))))
(defn r-fn [r t]
(conj r (state t)))
(reduce r-fn [] (range 10))
;;-> [0 1 1 1 1 1 1 1 1 1]
这更简洁地写成:
(reduce #(conj %1 (state %2)) [] (range 10))
答案 1 :(得分:2)
嗯,那是因为reduce函数应该正好采用2个参数:累加器和来自coll的项目,如果在reduce
调用期间没有提供累加器,则会减少bur,减少的第一步应用于前2个值来自coll:
(reduce + '(1 2 3 4))
确实是(+ (+ (+ 1 2) 3) 4)
但这不是你所需要的:
user> (map state (range 10))
(0 1 1 1 1 1 1 1 1 1)
因为您不希望将缩减为单个值,而是将映射每个值转换为另一个