Ramda — 提取两个属性并将一个附加到另一个 pointfree 样式
Ramda — extract two properties and append one to the other pointfree style
我有一些数据的形式:
const data = {
list: [1, 2, 3],
newItem: 5
}
我想创建一个函数,将 newItem
的值追加到 list
上,从而得到这个新版本的 data
:
{
list: [1,2,3,5],
newItem: 5,
}
(最终,我会在将 newItem 移入列表后将其删除,但我正在尝试简化此问题的问题)。
我正在尝试使用 pointfree 风格和 Ramda.js 作为学习经验。
这是我目前的位置:
const addItem = R.assoc('list',
R.pipe(
R.prop('list'),
R.append(R.prop('newItem'))
)
)
的想法是生成一个接受data
的函数,但在这个例子中,对R.append
的调用也需要对数据的引用,我试图避免明确提及[=15] =] 为了保持 Pointfree 风格。
这可以不提 data
吗?
如果我没理解错的话,您想从 {x:3, y:[1,2]}
转到 [1,2,3]
。这是一种方法:
const fn = compose(apply(append), props(['x', 'y']))
fn({x:3, y:[1,2]});
//=> [1,2,3]
const addItem = R.chain
( R.assoc('list') )
( R.converge(R.append, [R.prop('newItem'), R.prop('list')]) );
const data = {
list: [1, 2, 3],
newItem: 5
};
console.log(addItem(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
原因如下:
首先我们可以看看当前 addItem
在没有点自由时应该是什么样子:
const addItem = x => R.assoc('list')
(
R.pipe(
R.prop('list'),
R.append(R.prop('newItem')(x))
)(x)
)(x);
console.log(addItem({ list: [1, 2, 3], newItem: 5 }));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
它需要一些数据并在三个地方使用它。我们可以重构一下:
const f = R.assoc('list');
const g = x => R.pipe(
R.prop('list'),
R.append(R.prop('newItem')(x))
)(x)
const addItem = x => f(g(x))(x);
console.log(addItem({ list: [1, 2, 3], newItem: 5 }));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
x => f(g(x))(x)
部分可能不是很明显,但查看 list of common combinators in JavaScript 可以识别为 S_:
Name
#
Haskell
Ramda
Sanctuary
Signature
chain
S_³
(=<<)²
chain²
chain²
(a → b → c) → (b → a) → b → c
因此x => f(g(x))(x)
可以简化为R.chain(f)(g)
.
这留下了 g
,它仍然采用一个参数并在两个地方使用它。最终目标是从一个对象中提取两个属性并将它们传递给 R.append()
,这可以更容易地(和 pointfree)用 R.converge()
表示为:
const g = R.converge(R.append, [R.prop('newItem'), R.prop('list')]);
将 f
和 g
替换回
const addItem = R.chain
( R.assoc('list') )
( R.converge(R.append, [R.prop('newItem'), R.prop('list')]) );
正如关于 customcommander 的回答的讨论所示,有两种不同的可能解释。
如果你只想接收[1, 2, 3, 5]
,那么你可以像customcommander那样做,或者我会选择的方式:
const fn1 = lift (append) (prop ('newItem'), prop ('list'))
但是如果你想要像 {list: [1, 2, 3, 5], newItem: 5}
这样的东西,那么你可以在 applySpec
中使用上面的内容并将其与合并结合起来,如下所示:
const fn2 = chain (mergeLeft, applySpec ({list: fn1}))
这是一个片段:
const fn1 = lift (append) (prop ('newItem'), prop ('list'))
const fn2 = chain (mergeLeft, applySpec ({list: fn1}))
const data = {list: [1, 2, 3], newItem: 5}
console .log (fn1 (data)) //=> [1, 2, 3, 5]
console .log (fn2 (data)) //=> {list: [1, 2, 3, 5], newItem: 5}
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
<script> const {lift, append, prop, chain, mergeLeft, applySpec} = R </script>
第二个有点笨拙,一旦你内联 fn1
。它在两个地方重复 属性 list
,这总是困扰着我。但是暂时没有好的解决办法
我有好几次想要 R.evolve
和 R.applySpec
的组合,它像 evolve
一样在外部工作,让您只指定需要更改的属性,但是其转换函数被赋予整个输入对象,而不仅仅是相应的 属性.
有了类似的东西,这可能看起来像
const f3 = evolveSpec ({
list: ({list, newItem}) => [...list, newItem]
})
或使用上面的:
const f3 = evolveSpec ({
list: lift (append) (prop ('newItem'), prop ('list'))
})
我认为这可能是包含在 Ramda 中的有用候选者。
我有一些数据的形式:
const data = {
list: [1, 2, 3],
newItem: 5
}
我想创建一个函数,将 newItem
的值追加到 list
上,从而得到这个新版本的 data
:
{
list: [1,2,3,5],
newItem: 5,
}
(最终,我会在将 newItem 移入列表后将其删除,但我正在尝试简化此问题的问题)。
我正在尝试使用 pointfree 风格和 Ramda.js 作为学习经验。
这是我目前的位置:
const addItem = R.assoc('list',
R.pipe(
R.prop('list'),
R.append(R.prop('newItem'))
)
)
的想法是生成一个接受data
的函数,但在这个例子中,对R.append
的调用也需要对数据的引用,我试图避免明确提及[=15] =] 为了保持 Pointfree 风格。
这可以不提 data
吗?
如果我没理解错的话,您想从 {x:3, y:[1,2]}
转到 [1,2,3]
。这是一种方法:
const fn = compose(apply(append), props(['x', 'y']))
fn({x:3, y:[1,2]});
//=> [1,2,3]
const addItem = R.chain
( R.assoc('list') )
( R.converge(R.append, [R.prop('newItem'), R.prop('list')]) );
const data = {
list: [1, 2, 3],
newItem: 5
};
console.log(addItem(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
原因如下:
首先我们可以看看当前 addItem
在没有点自由时应该是什么样子:
const addItem = x => R.assoc('list')
(
R.pipe(
R.prop('list'),
R.append(R.prop('newItem')(x))
)(x)
)(x);
console.log(addItem({ list: [1, 2, 3], newItem: 5 }));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
它需要一些数据并在三个地方使用它。我们可以重构一下:
const f = R.assoc('list');
const g = x => R.pipe(
R.prop('list'),
R.append(R.prop('newItem')(x))
)(x)
const addItem = x => f(g(x))(x);
console.log(addItem({ list: [1, 2, 3], newItem: 5 }));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
x => f(g(x))(x)
部分可能不是很明显,但查看 list of common combinators in JavaScript 可以识别为 S_:
Name | # | Haskell | Ramda | Sanctuary | Signature |
---|---|---|---|---|---|
chain | S_³ | (=<<)² | chain² | chain² | (a → b → c) → (b → a) → b → c |
因此x => f(g(x))(x)
可以简化为R.chain(f)(g)
.
这留下了 g
,它仍然采用一个参数并在两个地方使用它。最终目标是从一个对象中提取两个属性并将它们传递给 R.append()
,这可以更容易地(和 pointfree)用 R.converge()
表示为:
const g = R.converge(R.append, [R.prop('newItem'), R.prop('list')]);
将 f
和 g
替换回
const addItem = R.chain
( R.assoc('list') )
( R.converge(R.append, [R.prop('newItem'), R.prop('list')]) );
正如关于 customcommander 的回答的讨论所示,有两种不同的可能解释。
如果你只想接收[1, 2, 3, 5]
,那么你可以像customcommander那样做,或者我会选择的方式:
const fn1 = lift (append) (prop ('newItem'), prop ('list'))
但是如果你想要像 {list: [1, 2, 3, 5], newItem: 5}
这样的东西,那么你可以在 applySpec
中使用上面的内容并将其与合并结合起来,如下所示:
const fn2 = chain (mergeLeft, applySpec ({list: fn1}))
这是一个片段:
const fn1 = lift (append) (prop ('newItem'), prop ('list'))
const fn2 = chain (mergeLeft, applySpec ({list: fn1}))
const data = {list: [1, 2, 3], newItem: 5}
console .log (fn1 (data)) //=> [1, 2, 3, 5]
console .log (fn2 (data)) //=> {list: [1, 2, 3, 5], newItem: 5}
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
<script> const {lift, append, prop, chain, mergeLeft, applySpec} = R </script>
第二个有点笨拙,一旦你内联 fn1
。它在两个地方重复 属性 list
,这总是困扰着我。但是暂时没有好的解决办法
我有好几次想要 R.evolve
和 R.applySpec
的组合,它像 evolve
一样在外部工作,让您只指定需要更改的属性,但是其转换函数被赋予整个输入对象,而不仅仅是相应的 属性.
有了类似的东西,这可能看起来像
const f3 = evolveSpec ({
list: ({list, newItem}) => [...list, newItem]
})
或使用上面的:
const f3 = evolveSpec ({
list: lift (append) (prop ('newItem'), prop ('list'))
})
我认为这可能是包含在 Ramda 中的有用候选者。