我正在尝试编写返回镜头的功能,以生产新镜头并以无点样式进行操作。
这可能是关于函数组成的更一般的问题。镜头只是个案例研究。我对镜头没有特别的兴趣,但是我想知道如何无点地组合这些功能的一般模式。
const obj = {a: {x: 0}, b: {x: 42}};
// this won't work, but I want it to work
const pointFreeComposedLens = R.compose(R.lensProp, R.lensProp('x'));
R.view(pointFreeComposedLens('a'), obj); // returns 'undefined'
// this works
const pointyComposedLens = key => R.compose(R.lensProp(key), R.lensProp('x'));
R.view(pointyComposedLens('a'), obj); // returns '0'
组成函数的模式是什么,这样我就不必继续重写组成管线中第一个函数的参数了?
举个令人震惊的例子:
const deepLens = (a, b, c) => R.lensPath([a, b, c]);
// This works, but is tedious & verbose
const extraDeep = (a, b, c, x) => R.compose(deepLens(a,b,c), R.lensProp(x));
const gammaDeep = (a, b, c, y) => R.compose(deepLens(a,b,c), R.lensProp(y));
// Doesn't work, but it would be nicer to write:
const extraDeep = x => R.compose(deepLens, R.lensProp(x));
// and call it like so:
R.view(extraDeep('a','b','c','x'), obj);
答案 0 :(得分:2)
我知道您仅以镜片为例,但这是从镜片中获得我认为想要的行为的一种方法。
const {lensPath, compose, lens, view} = R
const deepLens = (a, b, c) => lensPath([a, b, c]);
const deeper = (lens, ...args) => compose(lens, lensPath(args))
const cLens = deepLens('a', 'b', 'c')
const obj = {a: {b: { c: {d: 1, e: 2, f: {g: 3, h: 4, i: {j: 5, k: 6}}}}}}
console.log(view(cLens, obj)) //=> {d: 1, e: 2, f: {g: 3, h: 4, i: {j: 5, k: 6}}}
console.log(view(deeper(cLens, 'f', 'g'), obj)) //=> 3
const fLens = deeper(cLens, 'f')
console.log(view (fLens, obj)) //=> {g: 3, h: 4, i: {j: 5, k: 6}}
const jLens = deeper(cLens, 'f', 'i', 'j')
// or jLens = deeper(fLens, 'i', 'j')
console.log(view(jLens, obj)) //=> 5
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
对于更广泛的构图问题,镜头通常是Ramda之类的图书馆的特例,因为构图的顺序与通常预期相反。 (这里的技术原因太多了。)
但这就是为什么这不起作用:
const extraDeep = x => R.compose(deepLens, R.lensProp(x));
Ramda确实允许构图链中的第一个功能(compose
的最右边,pipe
的最左边)接收其他参数。但是当镜头构图的构图顺序颠倒时,它不起作用你可能会喜欢什么。
因此,如果您在其他情况下也遇到构图方面的类似问题,请打开一个单独的问题。我很想知道您在寻找什么。
答案 1 :(得分:1)
Rest参数会将代码缩短为:
const extraDeep = (...rest) => last => R.compose(deepLens(...rest), R.lensProp(last))(rest.pop());
但是我不确定那是否真的很优雅。
答案 2 :(得分:1)
如果您打算编写一个接受路径和对象的函数,
那么path
已经存在:
R.path(['a', 'b'], {a: {b: 10}}); //=> 10
如果您想删除某些函数中的某些参数,可以deepLens
进行如下重写:
const deepLens = R.unapply(R.lensPath);
此无点版本具有附加优势,即它不仅限于三个参数。它将与任意数量的参数一起使用:
deepLens('a', 'b'); //=> R.lensPath(['a', 'b']);
deepLens('a', 'b', 'c'); //=> R.lensPath(['a', 'b', 'c']);
deepLens('a', 'b', 'c', 'd'); //=> R.lensPath(['a', 'b', 'c', 'd']);