Reputation: 17574
I am learning Ramda and I am trying to use pipe
. To this effect I made this simple example that doesn't work:
var getSQLQuery = ( { lang } ) => `My query is ${lang}`;
var addAnd = str => str + " and";
var getMarket = country => data => `${data} my country is ${country}`;
var comp = ( country, queryParams ) => R.pipe(
getSQLQuery( queryParams ),
addAnd,
getMarket( country ),
R.tap( console.log )
)(country, queryParams);
comp("Spain", {lang: "uk"}); //Blows Up!?
The error I get is
First argument to _arity must be a non-negative integer no greater than ten
I don't know how to fix this. How can I do it?
Upvotes: 1
Views: 3890
Reputation: 50797
There are many ways one could write such a function. I know your goal is to learn how to use pipe
, but let me first show a technique that starts with something similar to your functions:
const getSQLQuery = ( { lang } ) => `My query is ${lang}`;
const getMarket = country => `my country is ${country}`;
const flipAndJoin = pipe(reverse, join(' and '))
const comp = useWith(unapply(flipAndJoin), [getMarket, getSQLQuery])
comp("Spain", {lang: "uk"}); //=> ""My query is uk and my country is Spain"
Now the questions are:
pipe
work as desired?It's simple: pipe
takes a number of functions as parameters, with at least one required. The first argument you supply is getSQLQuery( queryParams )
, which is the result of calling getSQLQuery
with an argument. That is a string, not a function. So when you try to wrap this in pipe
, it fails. (The note about 'arity' has to do with the internals of Ramda: it uses the first function to pipe
in order to determine how many parameters the resulting function should take.)
I gave an answer up above. The answer from MarioF does so with minimal change to your initial functions.
But none of these are as simple as
const comp2 = (country, queryParams) =>
`My query is ${queryParams.lang} and my country is ${country}`
comp2("Spain", {lang: "uk"}); //=> ""My query is uk and my country is Spain"
pipe
work as desired?You need to realize what pipe
does.
Think of a function like this:
const getUpperAddr(userName, collection) {
const configStr = getUserConfig(userName, collection);
const config = JSON.parse(configStr);
const address = prop('address')(config);
const addrLine1 = prop('addrLine1')(address);
const upperAddr = toUpper(addrLine1);
return upperAddr;
}
Forgetting the details, especially of how getUserConfig
works, and forgetting any potential errors, we can see one interesting feature of this function: each successive local variable is created by applying a function to the one before. The only exception to this is the first one, which uses the parameters to the function. The result is the final local variable.
pipe
is simply a way to make this more declarative, and remove the need for all the local variables (and even the parameter names.) This is equivalent:
const getUpperAddr = pipe(
getUserConfig,
JSON.parse,
prop('address'),
prop('addrLine1'),
toUpper
);
This has the same signature as the above and returns the same result for the same input. If you can write your function in the first format, you can mechanically change to pipe
. After a while, this becomes second nature, and you can skip the first step.
Upvotes: 10
Reputation: 3078
In answer to the core question "how to use x with multiple arguments", technically you can use R.nthArg, but that doesn't immediately help you pass data down the pipe.
In my opinion, it's better to pass in an array - or use rest parameters. This works:
//Kept as original
var getSQLQuery = ( { lang } ) => `My query is ${lang}`;
var addAnd = str => str + " and";
var getMarket = country => data => `${data} my country is ${country}`;
//only modified this function
const comp = (...args) =>
getMarket(args[0]) (
R.compose(addAnd, getSQLQuery)(args[1])
);
comp("Spain", {lang: "uk"});
Though I don't think R.compose
really makes that any easier to reason about. Maybe if it's separated out into a named function like this?
const enhanceQuery = R.compose(addAnd, getSQLQuery)
const comp = (...args) =>
getMarket(args[0]) (enhanceQuery(args[1]));
Upvotes: 1
Reputation: 47279
It is quite arguable whether this makes the code more readable than just using a single function, but this way you get what you are looking for:
var getSQLQuery = (_, {lang}) => `My query is ${lang}`;
var addAnd = str => str + " and";
var getMarket = country => data => `${data} my country is ${country}`;
var comp = ( country, queryParams ) => R.pipe(
getSQLQuery,
addAnd,
getMarket( country ),
R.tap( console.log )
)(country, queryParams);
comp("Spain", {lang: "uk"});
Upvotes: 2