编写 Ramda 函数
Compose Ramda Functions
您好,我正在学习 Ramda
库并且很喜欢它。我正在尝试练习一些函数概念,例如 curry
和 immutability
。下面我有一些代码,基本上是尝试 assoc
来自一个 object
的值并将其复制到另一个 object
。第一个 object
kdlJsonObj
具有 cost
值,我想将其附加到另一个对象
//object from API
var kdlJsonObj = [
{name: 'AAA COOPER TRANSPORTATION', cost: 33},
{name: 'OLD DOMINION FREIGHT LINE, INC', cost: 22},
{name: 'ROADRUNNER TRANSPORTATION SERVICES', cost: 31}
]
// objects to assoc
var aaa = {shortName: 'AAA Cooper', name: 'AAA COOPER TRANSPORTATION' }
var odlf = {shortName: 'Old Dominion', name: 'OLD DOMINION FREIGHT LINE, INC'}
var rr = {shortName: 'Road Runner', name: 'ROADRUNNER TRANSPORTATION SERVICES'}
// Ramda functions that I would like to compose
var namePropEq = R.propEq('name')
var namePropEqAAA = namePropEq('AAA COOPER TRANSPORTATION')
var findAAA = R.find(namePropEqAAA, kdlJsonObj)
var costProp = R.prop('cost')
var costAAA = costProp(findAAA)
var assocCost = R.assoc('cost')
var assocCostAAA = assocCost(costAAA)(aaa)
assocCostAAA // => {shortName: "AAA Cooper", name: "AAA COOPER TRANSPORTATION", cost: 33}
我希望能够编写这些函数集,使其成为一种更加无意义的编码风格,在我进行调用之前不提供任何数据。理想情况下,它应该是 var assocCostAAA = composeAssoc(namePropEqAAA)(aaa)
之类的东西,我可以只调用一个函数。由于 arity 规则
,我不确定 compose
这个函数是否可行
var composeAssoc = R.compose(
R.assoc('cost'),
R.find(name, kdlJsonObj), // has two arity so i believe this is not correct
R.propEq(name))
我愿意用不同的方式来做这件事。例如使用 Ramda
函数,例如 R.pluck
,R.filter
甚至 R.lens
。但我希望它成为一个 composed/declarative 函数。
我希望有更优雅的方式,但这是无意义的:
const source = [
{ name: 'Aaa', cost: 1 },
{ name: 'Bee', cost: 2 },
{ name: 'Cee', cost: 3 },
];
const target = { shortName: 'A', name: 'Aaa' };
const func =
R.chain(
R.assoc('cost'), // ('cost', 1, target) -> output
R.compose(
R.prop('cost'), // ('cost', {name: 'Aaa', cost: 1}) -> 1
R.compose(
R.find(R.__, source), // (predicate, source) -> {name: 'Aaa', cost: 1}
R.compose(
R.propEq('name'), // ('name', 'Aaa' ) -> predicate
R.prop('name'), // ('name', target) -> 'Aaa'
),
),
),
);
const targetWithCost = func(target);
输出:{"cost": 1, "name": "Aaa", "shortName": "A"}
哦,是的……这个好一点:
const func =
R.chain(
R.assoc('cost'), // ('cost', 1, target) -> :)
R.compose(
R.prop('cost'), // ('cost', {name: 'Aaa', cost: 1}) -> 1
R.find(R.__, source), // (predicate, source) -> {name: 'Aaa', cost: 1}
R.eqProps('name'), // ('name', target) -> predicate
),
);
输出:{"cost": 1, "name": "Aaa", "shortName": "A"}
正如 Scott 指出的那样,我的解决方案并非完全无点,因此作为实验,我想出了这个完全无点的代码:
const func =
R.converge(
R.assoc('cost'), // ('cost', 1, target) -> {shortName: 'A', name: 'Aaa', cost: 1}
[
R.useWith( // (target, source) -> 1
R.compose( // (predicate, source) -> 1
R.prop('cost'), // ('cost', {name: 'Aaa', cost: 1}) -> 1
R.find, // (predicate, source) -> {name: 'Aaa', cost: 1}
),
[
R.eqProps('name'), // ('name', target) -> predicate
R.identity, // source -> source
],
),
R.identity, // (target, source) -> target
],
);
const targetWithCost = func(target, source);
这样做非常简单,不用担心无点:
const {curry, assoc, prop, find, eqProps} = R;
const kdlJsonObj = [
{name: 'AAA COOPER TRANSPORTATION', cost: 33},
{name: 'OLD DOMINION FREIGHT LINE, INC', cost: 22},
{name: 'ROADRUNNER TRANSPORTATION SERVICES', cost: 31}
]
const companies = [
{shortName: 'AAA Cooper', name: 'AAA COOPER TRANSPORTATION' },
{shortName: 'Old Dominion', name: 'OLD DOMINION FREIGHT LINE, INC'},
{shortName: 'Road Runner', name: 'ROADRUNNER TRANSPORTATION SERVICES'},
{shortName: 'Flintstone', name: 'FRED FLINTSTONE HAULING'}
]
const [aaa, odfl, rr, ff] = companies
const addCost = curry((costs, company) => assoc(
'cost',
prop('cost', find(eqProps('name', company), costs)),
company
))
console.log(addCost(kdlJsonObj)(rr))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
虽然这可以变得毫无意义,但结果的可读性可能会差很多。我尝试将 point-free 视为一种工具,当(且仅当)它提高可读性时使用,但你的里程可能会有所不同。
这也不做任何真正的错误检查。如果没有找到匹配的值,就加上cost: undefined
.
还要注意这是多么脆弱。 post 中 AAA 的两个版本之间存在拼写差异。如果它们不是从同一源生成的,那么如果您依赖于长字符串之间的匹配,您可能会遇到这样的问题。我对此没有特别的建议,但值得研究。
@Scott Sauyet 我更新了你的一些原因有几个。 1) 我在 NetSuite 上,他们使用 Rhino 6
而没有使用 ES6
规范。 2)我是新手,所以虽然我喜欢你非常简洁的风格,但我把我的风格分解了一点,这样我就能更好地理解它。谢谢您的帮助。
var kdlJsonObj = [
{name: 'AAA COOPER TRANSPORTATION', cost: 33},
{name: 'OLD DOMINION FREIGHT LINE, INC', cost: 22},
{name: 'ROADRUNNER TRANSPORTATION SERVICES', cost: 31}
]
var aaa = {shortName: 'AAA Cooper', name: 'AAA COOPER TRANSPORTATION' }
var odlf = {shortName: 'Old Dominion', name: 'OLD DOMINION FREIGHT LINE, INC'}
var rr = {shortName: 'Road Runner', name: 'ROADRUNNER TRANSPORTATION SERVICES'}
var addCost = function(costs, company) {
var comp = R.find(R.eqProps('name', company), costs)
var cost = R.prop('cost', comp)
return R.assoc('cost', cost, company)
}
var addCostCurried = R.curry(addCost)(kdlJsonObj)
var rrAssocatied = addCostCurried(rr)
var odflAssocatied = addCostCurried(odlf)
var aaaAssocatied = addCostCurried(aaa)
您好,我正在学习 Ramda
库并且很喜欢它。我正在尝试练习一些函数概念,例如 curry
和 immutability
。下面我有一些代码,基本上是尝试 assoc
来自一个 object
的值并将其复制到另一个 object
。第一个 object
kdlJsonObj
具有 cost
值,我想将其附加到另一个对象
//object from API
var kdlJsonObj = [
{name: 'AAA COOPER TRANSPORTATION', cost: 33},
{name: 'OLD DOMINION FREIGHT LINE, INC', cost: 22},
{name: 'ROADRUNNER TRANSPORTATION SERVICES', cost: 31}
]
// objects to assoc
var aaa = {shortName: 'AAA Cooper', name: 'AAA COOPER TRANSPORTATION' }
var odlf = {shortName: 'Old Dominion', name: 'OLD DOMINION FREIGHT LINE, INC'}
var rr = {shortName: 'Road Runner', name: 'ROADRUNNER TRANSPORTATION SERVICES'}
// Ramda functions that I would like to compose
var namePropEq = R.propEq('name')
var namePropEqAAA = namePropEq('AAA COOPER TRANSPORTATION')
var findAAA = R.find(namePropEqAAA, kdlJsonObj)
var costProp = R.prop('cost')
var costAAA = costProp(findAAA)
var assocCost = R.assoc('cost')
var assocCostAAA = assocCost(costAAA)(aaa)
assocCostAAA // => {shortName: "AAA Cooper", name: "AAA COOPER TRANSPORTATION", cost: 33}
我希望能够编写这些函数集,使其成为一种更加无意义的编码风格,在我进行调用之前不提供任何数据。理想情况下,它应该是 var assocCostAAA = composeAssoc(namePropEqAAA)(aaa)
之类的东西,我可以只调用一个函数。由于 arity 规则
compose
这个函数是否可行
var composeAssoc = R.compose(
R.assoc('cost'),
R.find(name, kdlJsonObj), // has two arity so i believe this is not correct
R.propEq(name))
我愿意用不同的方式来做这件事。例如使用 Ramda
函数,例如 R.pluck
,R.filter
甚至 R.lens
。但我希望它成为一个 composed/declarative 函数。
我希望有更优雅的方式,但这是无意义的:
const source = [
{ name: 'Aaa', cost: 1 },
{ name: 'Bee', cost: 2 },
{ name: 'Cee', cost: 3 },
];
const target = { shortName: 'A', name: 'Aaa' };
const func =
R.chain(
R.assoc('cost'), // ('cost', 1, target) -> output
R.compose(
R.prop('cost'), // ('cost', {name: 'Aaa', cost: 1}) -> 1
R.compose(
R.find(R.__, source), // (predicate, source) -> {name: 'Aaa', cost: 1}
R.compose(
R.propEq('name'), // ('name', 'Aaa' ) -> predicate
R.prop('name'), // ('name', target) -> 'Aaa'
),
),
),
);
const targetWithCost = func(target);
输出:{"cost": 1, "name": "Aaa", "shortName": "A"}
哦,是的……这个好一点:
const func =
R.chain(
R.assoc('cost'), // ('cost', 1, target) -> :)
R.compose(
R.prop('cost'), // ('cost', {name: 'Aaa', cost: 1}) -> 1
R.find(R.__, source), // (predicate, source) -> {name: 'Aaa', cost: 1}
R.eqProps('name'), // ('name', target) -> predicate
),
);
输出:{"cost": 1, "name": "Aaa", "shortName": "A"}
正如 Scott 指出的那样,我的解决方案并非完全无点,因此作为实验,我想出了这个完全无点的代码:
const func =
R.converge(
R.assoc('cost'), // ('cost', 1, target) -> {shortName: 'A', name: 'Aaa', cost: 1}
[
R.useWith( // (target, source) -> 1
R.compose( // (predicate, source) -> 1
R.prop('cost'), // ('cost', {name: 'Aaa', cost: 1}) -> 1
R.find, // (predicate, source) -> {name: 'Aaa', cost: 1}
),
[
R.eqProps('name'), // ('name', target) -> predicate
R.identity, // source -> source
],
),
R.identity, // (target, source) -> target
],
);
const targetWithCost = func(target, source);
这样做非常简单,不用担心无点:
const {curry, assoc, prop, find, eqProps} = R;
const kdlJsonObj = [
{name: 'AAA COOPER TRANSPORTATION', cost: 33},
{name: 'OLD DOMINION FREIGHT LINE, INC', cost: 22},
{name: 'ROADRUNNER TRANSPORTATION SERVICES', cost: 31}
]
const companies = [
{shortName: 'AAA Cooper', name: 'AAA COOPER TRANSPORTATION' },
{shortName: 'Old Dominion', name: 'OLD DOMINION FREIGHT LINE, INC'},
{shortName: 'Road Runner', name: 'ROADRUNNER TRANSPORTATION SERVICES'},
{shortName: 'Flintstone', name: 'FRED FLINTSTONE HAULING'}
]
const [aaa, odfl, rr, ff] = companies
const addCost = curry((costs, company) => assoc(
'cost',
prop('cost', find(eqProps('name', company), costs)),
company
))
console.log(addCost(kdlJsonObj)(rr))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
虽然这可以变得毫无意义,但结果的可读性可能会差很多。我尝试将 point-free 视为一种工具,当(且仅当)它提高可读性时使用,但你的里程可能会有所不同。
这也不做任何真正的错误检查。如果没有找到匹配的值,就加上cost: undefined
.
还要注意这是多么脆弱。 post 中 AAA 的两个版本之间存在拼写差异。如果它们不是从同一源生成的,那么如果您依赖于长字符串之间的匹配,您可能会遇到这样的问题。我对此没有特别的建议,但值得研究。
@Scott Sauyet 我更新了你的一些原因有几个。 1) 我在 NetSuite 上,他们使用 Rhino 6
而没有使用 ES6
规范。 2)我是新手,所以虽然我喜欢你非常简洁的风格,但我把我的风格分解了一点,这样我就能更好地理解它。谢谢您的帮助。
var kdlJsonObj = [
{name: 'AAA COOPER TRANSPORTATION', cost: 33},
{name: 'OLD DOMINION FREIGHT LINE, INC', cost: 22},
{name: 'ROADRUNNER TRANSPORTATION SERVICES', cost: 31}
]
var aaa = {shortName: 'AAA Cooper', name: 'AAA COOPER TRANSPORTATION' }
var odlf = {shortName: 'Old Dominion', name: 'OLD DOMINION FREIGHT LINE, INC'}
var rr = {shortName: 'Road Runner', name: 'ROADRUNNER TRANSPORTATION SERVICES'}
var addCost = function(costs, company) {
var comp = R.find(R.eqProps('name', company), costs)
var cost = R.prop('cost', comp)
return R.assoc('cost', cost, company)
}
var addCostCurried = R.curry(addCost)(kdlJsonObj)
var rrAssocatied = addCostCurried(rr)
var odflAssocatied = addCostCurried(odlf)
var aaaAssocatied = addCostCurried(aaa)