Hi am just learning the Ramda
library and loving it. I am trying to practice some functional concepts like curry
and immutability
. Below I have a little code that is basically trying to assoc
the value from one object
and copy that to another object
. The first object
kdlJsonObj
has the cost
value, that I would like to append that to another object
//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. I am not sure it is possible to compose
this function because of the arity rules
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
. 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"}
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"}
As Scott pointed out my solution was not completely point-free, so as an experiment I came up with this fully point-free code:
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);