新年快乐,上午研究了下 Transduce
var numbers = [1, 2, 3, 4]
var transducer = R.compose(R.map(R.add(1)), R.take(2))
console.log(transducer([1, 2, 3]))
console.log(R.append(R.__)(1, [2, 3]))
R.transduce(transducer, R.append(R.__), [], R.range(0, 5)) //=> [2, 3]

transducer :: number[] => number[]
R.append(R.__) :: (number[], number) => number[]
执行的顺序是先执行 transducer , 再执行 R.append(R.__), compose 里面是从右到左的。
但是在 clojure 里面顺序会有点不一样(仅只在 transduce 中的 comp),可能是另外一种实现方式,可以通过 R.into 来实现这种方式
(def xf (comp (filter odd?) (map inc)))
(transduce xf + (range 5))
;; => 6
(transduce xf + 100 (range 5))
;; => 106
这里是先 inc 再 filter 要不然结果不肯能是 6.
function run(transduceObj, arr, init) {
arr = arr.filter(transduceObj.f)
return arr.reduce(transduceObj.xf.f, init)
}
console.log(
R.transduce(
arr => {
// const ret = R.compose(R.map(R.add(1)), R.take(2))(arr)
// console.log(ret)
// return ret
console.log(arr)
const newArr = R.filter(n => n % 2 == 0, arr)
console.log(newArr)
console.log(run(newArr, [1, 2, 3, 4], 0))
return newArr
},
(a, b) => a + b,
1,
[1, 2, 3]
)
)
虽然范畴类型是这个,但是 transducer 是有标准的,比如有 step 啥的。
所以这里的 arr 实际并非是一个数组,尽管范畴来说是的,假如我们把它当成数组来处理会报错。
其实它是一个 transducer ,通过 R 的一些方法可以进行组合,比如 R.filter,假如使用 Array.filter 就报错,因为它不是 Array,不是 Array,不是 Array。
我们来看一下经过 R.filter 处理会变成什么。

处理前是 R.filter 处理之后,从 XWarp 变成了 XFilter,具体这个对象如何变换,和执行,那是 ramda 的工作,我根据这个结果,写了一个只能运行这一个对象的 Run 方法。运行的结果 6.
的结果则是 3

66 顺呀,33哥俩好呀~
const l = msg => () => console.log(msg)
var transducer = R.compose(
R.tap(l('map'), R.map(R.add(1))),
R.tap(l('take'), R.take(2))
)
R.into([], transducer, numbers) //=> [2, 3]

跟 clojure 行为类似的函数。
应用场景,假如你只是要对 reduce 之前对数组的部分进行过滤,使用 reduceWhile 的第一个参数可以帮助你断言。
假如是分组可以用 reduceBy,主要用来提取具有相同共性的对象。
var reduceToNamesBy = R.reduceBy((acc, student) => acc.concat(student.name), []);
var namesByGrade = reduceToNamesBy(function(student) { var score = student.score; return score < 65 ? 'F' : score < 70 ? 'D' : score < 80 ? 'C' : score < 90 ? 'B' : 'A';
});
var students = [{name: 'Lucy', score: 92}, {name: 'Drew', score: 85}, // ... {name: 'Bart', score: 62}];
namesByGrade(students);
根据第三个参数返回的 作为 key,value 则是 reduce 完的结果。
reduced 可以提前结束 reduce。
transduce 则是再 reduce 之前做一些 map filter take,可以随便自定义 transducer,到这吧。