Skip to content

Argumentation of Rambda’s partialCurry method

Dejan Toteff edited this page Jun 10, 2020 · 1 revision

Before touching the main topic, I’d like first to take a look at Ramda’s pathSatisfies method:

R.pathSatisfies(
  y => y > 0, 
  ['x', 'y'], 
  {x: {y: 2}}
); //=> true

So to use this method, we need to pass first function then path and finally the object.

Will you remember that first argument is the function or you will check the documentation every time you use it?

Now compare that to this hypothetical implementation:

const fn = y => y > 0

const path = ['x', 'y']
const obj = {x: {y: 2}}

R.pathSatisfies({fn, path, obj})

In the second example we exchange remembering order of passing arguments to R.pathSatisfies for remembering the pattern.

Which one is easier to write?

Which one is easier to read?

I let you answer these questions, but once I start typing a third argument to a function, something inside me screams: “This is wrong!”

Of course the second example doesn’t work with R.compose which in Ramda world is significant drawback. But the follow-up question is: “How often you need to use function with three arguments inside compose?”

Even if you need that type of method, you most probably will use it directly like in the first example. If that is the case, then it makes more sense to go for the second type of implementation.

So what goes for R.pathSatisfies applies to R.curry as well

Taken from Ramda documentation:

var addFourNumbers = (a, b, c, d) => a + b + c + d
var curriedAddFourNumbers = R.curry(addFourNumbers);
var f = curriedAddFourNumbers(1, 2);
var g = f(3);g(4); //=> 10

R.curry can be great if you write a library, but is that really the style you write your everyday functions?

Rambda’s partialCurry example:

const fn = ({a, b, c}) => {  
  return (a * b) + c
}
const curried = R.partialCurry(
  fn, 
  {a: 2}
)
curried({b: 3, c: 10}) //=> 16

So now I can write functions like this one taken from redis-fn library:

// ./methods/get.js
const get = ({redisClient,key}) => new Promise(
  (resolve, reject)=>{  
    redisClient.get(key, (err, result) => {
      if (!(err === null)) return reject(err)    
      resolve(result)  
    })
  })

module.exports = get

And export them with already initialized Redis instance:

// index.js
const get = require("./methods/get")

const redisFn = redisUrl => new Promise(resolve => {
  const redisClient = redisLib.createClient(options)
  redisClient.on("connect", () => {
    resolve({
      client:redisClient,
      get:R.partialCurry(get,{redisClient})
    })
  })
})

module.exports = redisFn

Final words

Usually when I want to add something to Rambda, it ends up in Rambdax(as I want to keep Rambda lean). But that was not the case with partialCurry as I found it particularly useful at the time of its development.