简体   繁体   English

撰写Ramda函数

[英]Compose Ramda Functions

Hi am just learning the Ramda library and loving it. 嗨,我只是学习Ramda库并喜欢它。 I am trying to practice some functional concepts like curry and immutability . 我正在尝试练习一些curryimmutability等功能性概念。 Below I have a little code that is basically trying to assoc the value from one object and copy that to another object . 下面我有一些代码,基本上是试图从一个object assoc值并将其复制到另一个object The first object kdlJsonObj has the cost value, that I would like to append that to another 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}

I would like to be able to compose these set of function make it a more point-free style of coding where no data is provided until I make the call. 我希望能够组合这些函数集,使其成为一种更加无点的编码样式,在进行调用之前,不提供任何数据。 Ideally it would be something like var assocCostAAA = composeAssoc(namePropEqAAA)(aaa) and I could just call one function. 理想情况下,它将类似于var assocCostAAA = composeAssoc(namePropEqAAA)(aaa) ,我可以只调用一个函数。 I am not sure it is possible to compose this function because of the arity rules 由于不确定规则,我不确定是否可以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))

I am open to doing it different ways. 我愿意以不同的方式来做。 Such as using Ramda functions like R.pluck , R.filter maybe even R.lens . 如使用Ramda像功能R.pluckR.filter甚至R.lens But I would love for it to be a composed/declarative function. 但我希望它能够成为组合/声明式函数。

I hope that there is a more elegant way, but this is point-free: 我希望有一种更优雅的方法,但这是没有意义的:

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

outputs: {"cost": 1, "name": "Aaa", "shortName": "A"} 输出: {"cost": 1, "name": "Aaa", "shortName": "A"}

Run with Ramda REPL here!! 在这里与Ramda REPL一起运行!!

Oh yes... this is a little bit better: 哦,是的。。。好一点了:

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

outputs: {"cost": 1, "name": "Aaa", "shortName": "A"} 输出: {"cost": 1, "name": "Aaa", "shortName": "A"}

Run with Ramda REPL here!! 在这里与Ramda REPL一起运行!!

As Scott pointed out my solution was not completely point-free, so as an experiment I came up with this fully point-free code: 正如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);

Run it here in the Ramda REPL 在Ramda REPL中在此处运行

It's pretty straightforward to do this without worrying about point-free: 做到这一点非常简单,无需担心无点数:

 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> 

While this could be made point-free, the result would likely be much less readable. 尽管可以将其设置为无点,但结果的可读性可能会大大降低。 I try to think of point-free as a tool to use when (and only when) it increases readability, but your mileage may vary. 我尝试将无点数作为一种工具(仅当它可以提高可读性时使用),但是您的里程可能会有所不同。

This also does not do any real error-checking. 这也不会进行任何真正的错误检查。 If the matching value is not found, it just adds cost: undefined . 如果找不到匹配的值,则只会添加cost: undefined

Also note how fragile this is. 还要注意这是多么脆弱。 There is a difference in spelling between the two versions of AAA in the post. 帖子中AAA的两个版本之间的拼写有所不同。 If they are not generated from the same source, you could have issues like this all over if you're depending on a match between long strings. 如果它们不是从同一来源生成的,那么如果您依赖长字符串之间的匹配,则可能会遇到类似这样的问题。 I don't have particular suggestions for this, but it's worth investigating. 我对此没有特别的建议,但值得调查。

@Scott Sauyet I updated your a little for a couple of reasons. @Scott Sauyet我出于几个原因对您进行了一些说明。 1) I am on NetSuite and they use Rhino 6 which is not using ES6 spec. 1)我在NetSuite上,他们使用的是Rhino 6 ,而后者未使用ES6规范。 2) I am new to this so although I like your very concise style I broke mine up a little so I could better understand it. 2)我对此并不陌生,因此尽管我喜欢您的简洁风格,但我还是将其分解了一些,以便更好地理解它。 Thank you for your help. 谢谢您的帮助。

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM