撰写Ramda函数

时间:2018-01-03 14:00:41

标签: javascript ramda.js declarative pointfree

您好我正在学习Ramda图书馆并喜欢它。我正在尝试练习一些功能性概念,例如curryimmutability。下面我有一些代码,它基本上试图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))

我愿意采取不同的方式。例如使用RamdaR.pluck函数,R.filter甚至R.lens。但我希望它能成为一个组合/声明的功能。

3 个答案:

答案 0 :(得分:2)

我希望有更优雅的方式,但这是无点的:

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"}

Run with Ramda REPL here!!

哦,是的......这有点好一点:

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"}

Run with Ramda REPL here!!

斯科特指出我的解决方案并非完全无点,所以作为一个实验,我想出了这个完全无点的代码:

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);

Run it here in the Ramda REPL

答案 1 :(得分:2)

这样做非常简单而不用担心无点:



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>
&#13;
&#13;
&#13;

虽然这可以毫无意义地进行,但结果的可读性可能会低得多。我试着将无点作为一种工具,当它(并且只有当它)增加可读性时使用,但你的里程可能会有所不同。

这也不会进行任何真正的错误检查。如果找不到匹配值,则只添加cost: undefined

还要注意这是多么脆弱。在帖子中,两个版本的AAA之间的拼写有所不同。如果它们不是从同一来源生成的,那么如果您依赖于长字符串之间的匹配,则可能会出现这样的问题。我对此没有特别的建议,但值得研究。

答案 2 :(得分:0)

@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)