I have this function, which is basically mapping request parameters and query parameters to a SQL statement:
function selectSingleResult(params, { order, limit, offset, fields, runset_id, txOffset, txFactor }) {
const transformer = R.when(R.equals('values'), R.compose(knex.raw.bind(knex), applyConversion({ txOffset, txFactor })))
const newFields = R.map(transformer , fields);
knex('myTable').select(...newFields) // etc...
Ideally, I would like to be able to define transformer outside the function so the function can just become:
const mapFields = R.map(transformer);
function selectSingleResult(params, { order, limit, offset, fields, runset_id, txOffset, txFactor }) {
knex('myTable').select(...mapFields(fields)) // etc...
The issue being that the applyConversion function needs arguments given to selectSingleResult.
This is a common issue I have with transform functions to map. They often require parameters other than the values being mapped over. In such cases, how can I write in point-free, or at least more testable style and not end up nesting functions so much?
It feels as though you're trying to go point-free in code where it doesn't make much sense. But there's a contrasting notion of destructuring a large set of fields from the second parameter that doesn't seem necessary, so this seems mostly confused. (It might actually be necessary: perhaps you're using order, limit, offset, and runset_id in the remainder of your main function.)
I think you can accomplish almost what you're asking by just introducing one more layer of calls, with something like this:
const transformer = (query) =>
R .when (R .equals ('values'), field => knex .raw (applyConversion (query) (field)))
const mapFields = R.pipe (transformer, map)
const selectSingleResult = (params, query) => {
knex ('myTable') .select (... mapFields (query) (query .fields))
// etc...
}
I name the second parameter to your main function query; it's a guess, and if that's confusing, replace all the instances of query with foo or with something meaningful to you.
Note that mapFields could also be written as const mapFields = (query) => R.map (transformer (query)), but the version above seems simpler. Also note that I simplified transformer a bit. I simply don't see any reason to try to go point-free, when you can't get all the way there. And trying to mix point-free code with OO constructs such as knex .raw just seems to confuse things.
If I read the code correctly, we also might rewrite transformer like this:
const transformer = (query) => (field) =>
field == 'values' ? knex .raw (applyConversion (query) ('values')) : field
but I can't decide if that is an improvement or not.
Related
I'm trying to write a function composition that partially applies an argument at each step and ends up calling a curried two-argument function.
There is a set of example functions to compose. I removed the calculations that there are supposed to do as they are not relevant to the problem but let's assume that every argument is required.
const getDayLimit = () => {
return 10
}
const getIpCount = ip => dayLimit => {
return 99
}
const getIp = (deviceId, headerIp) => {
// TODO: use Result monad to handle errors
if (!deviceId && !headerIp) {
throw new Error('Ip not provided')
}
return deviceId || headerIp
}
And the composition attempt:
const validateIp = R.compose(
f => f(getDayLimit()),
getIpCount,
getIp
)
validateIp(1, 2)
In the first step, getIp received two values and based on them returns an ip that is then partially applied to getIpCount, now the composition return a function that expects the dayLimit argument that needs to be computed first.
The plain way of doing this could be: f => f(getAccountLimit()).
I'd like to remove such function creation f => f... and pass it point-free.
Here's a helper function that solves this but is not handling all cases such as passing arguments to the result function:
const applyResult = result => f => R.compose(f, result)()
then I could do:
const result = R.compose(
applyResult(getDayLimit),
getIpCount,
getIp
)
It seems too hacky for me and not substantial for my further use. I'd rather avoid writing my own helper function for this kind of problem.
Is there a functional way of computing arguments before partially applying them to a function? It seems to be a pretty common case in my mind, though perhaps I'm not thinking about the problem correctly.
Is my thinking incorrect about this problem and function composition?
What is a good approach to handling such a case with a function with two parameters in a composition?
Can this case of partially applying function arguments with each step be handled in a function composition?
Thank you!
I think I would use a continuation which, as I understand it, represents a computation that has been interrupted:
const cont = x => f => f(x);
With a continuation, you get x before f. Instead of doing f(x) you do cont(x)(f) which behind the scene just does f(x) for you.
At the time of composing the functions together you already know the value of x which is getDayLimit(), you just don't know the value of f yet which is known only when result is applied to the first two initial parameters.
So here's what I'd do:
const result = R.compose( cont(getDayLimit())
, getIpCount
, getIp);
Is there a functional way of computing arguments before partially applying them to a function?
I would simply note that you apply a function to a value (not the other way round)
I'm learning functional programming and I'm trying to refactor a piece of old code using lodash FP.
Here's the code I have:
_.filter(x => isIdInArray(x)(xs))(otherXs)
It's too complicated to read and makes me feel a bit weird (smell ?)
My problem is that x value, that is the first argument of isIdInArray is declared this way:
const getId = _.get('id');
const isIdInArray = _.compose(_.includes, getId);
I can't use my lodash filter function this way:
_.filter(isIdInArray(xs))(otherXs)
I don't even know if it's feasible, but I'm pretty sure I can do something clearer or more readable.
Do you have some ideas ?
Try not to stuff all the fancy features that lodash gives you into a single line there.
Having a complex mechanism in one line may seem nice, but if you can't read it anymore its not very helpful at all.
For managing collections i usually use approaches like this:
var collection = [{id: 'a', someField: 1}, {id:'b', someField: 2}];
var theIdsYoureLookingFor = ['a'];
var filtered = collection
.filter(anyObject => _.includes(theIdsYoureLookingFor, anyObject.id))
.map(anyObject => anyObject.someField);
alert(filtered); // alerts 1
Which parses a collection of objects, filters for those who have an id that you consider valid and then maps those objects to a certain field.
Also don't ever use variable names like: x, xs
If you're writing production code, I recommend using a higher-level function. In your particular case I'd say you need _.intersectionBy:
const keepIfIdInArray = _.intersectionBy('id'); // 'id' can be replaced by your getId
const keepIfIdInOtherXs = keepIfIdInArray(otherXs);
keepIfIdInOtherXs(xs);
If you're doing this as an exercice, then I'd say you may need to decompose a little more. Notice that in lodash/fp, _.includes is curried so you should be able to write the following:
const getId = _.get('id');
const isIdInArray = arr => _.compose(_.includes(arr), getId);
const isIdInOtherXs = isIdInArray(otherXs);
_.filter(isIdInOtherXs)(xs);
I am composing a series of function but I wonder what's the best way to achieve what I want first this is how I compose:
const composeP = (...fns) => fns.reduce((f, g) => async (...args) => f(await g(...args)))
const profileSummary = profileData => composeP(createProfileSummary, getMKAProfile)(profileData)
now what I want is to do a check and if profileData which is my input is a certain string e.g. "cantbesearched" I want to return a value immediately to "profileSummary" variable instead of executing previous functions...
so is it possible to create a "filterWords" function, put it in front of the composition like this:
const profileSummary = profileData => composeP(createProfileSummary, getMKAProfile, filterWords)(profileData)
and if certain words are detected, skip previous functions on the left then return a value.
Is it possible to create a "filterWords" function to be put it in front of the composition?
No. What you want to do is branching, which is not possible with function composition.
What you can do is compose functions that work on a type which provides an error path, like Maybe or Either. (You can also consider exceptions as a builtin error path for every type, so just throw).
Oh wait, you already are doing that! You didn't write a plain function composition compose, you wrote composeP which uses monadic Kleisli composition - and promises do have such an error path:
function filterWords(word) {
return word == "cantbesearched"
? Promise.reject(new Error("filtered for your safety"))
: Promise.resolve(word);
}
I decided to code a simple todo app using Ramda, but I have been stuck with one refactoring related issue. Here're two functions that I think could be refactored:
const isItemCompleted = R.pipe(
R.prop("states"),
R.contains("completed")
)
const isItemEdited = R.pipe(
R.prop("states"),
R.contains("editing")
);
As you can see, there is some code duplication and this would get even messier if I had more states. I have been trying to isolate the duplicated functionality as such:
const statesContains = R.flip(R.pipe(
R.prop('states'),
R.contains()
))
//I would like to use it like this:
const isItemCompleted = statesContains("completed")
const isItemEdited = statesContains("editing")
But I just cannot wrap my head around this. I can make it work with different argument ordering, but I would like to follow the data-last rule to create concise functions.
The data being passed to these isItemCompleted and isItemEdited functions could be something like this:
let item = {states:["editing", "complete"]};
isItemCompleted(item); //true
Any (functional) ideas?
There are several ways to go with this.
Perhaps the most straightforward is
const statesContains = R.curry(
(state, item) => R.contains(state, R.prop('states', item))
);
const isItemCompleted = statesContains("completed");
But it's reasonable to want to abstract this a bit, to allow the property to be searched to vary as well. So you could write:
const propContains = R.curry(
(propName, state, item) => R.contains(state, R.prop(propName, item))
);
const editorsContains = propContains('editors')
const edFred = editorsContains('fred');
// or edFred = propContains('editors', 'fred');
Both of these are reasonable. But Ramda has a function which reads really well, and will serve these needs pretty well, where. With this, you can simply write:
const isItemCompleted = R.where({states: R.contains('completed')});
This, I believe, is the simplest approach if you're looking for one-offs. But both of the above could help you create reusable functions.
You can see all this in action in the Ramda REPL
I am trying to understand the ways of using functional style in JavaScript in practice. I've created a simple set of functions to process a string, but I feel I am doing it conceptually wrong because it looks just like imperative style, even though I don't mutate input and don't change state of the app inside the functions.
Here is how it looks:
var LineParser = require('../modules/LineParser');
var inputLine = 'A line with multiple spaces';
var outputLine = LineParser().formatSpaces(inputLine);
// 'A line with multiple spaces'
outputLine = LineParser().capitalize(outputLine);
// 'A Line With Multiple Spaces'
outputLine = LineParser().formatSomethingElse(outputLine);
// Some more formatting, then do further processing with outputLine
If I run the sequence using callbacks, it is going to become an ugly set of nested callbacks really quickly when I have, say, 10 simple processing functions.
If I add methods chaining, the idea of prototype methods looks against functional style too, because functions in the chain will depend on previous state, not only on the input they get.
What should I do to make it look nicer in a functional style?
Update: After deeper research I found topic named Function Composition. It seems to be a proper solution to the problem and is one of the basic things from the functional world.
Here is the function I use to compose multiple functions into one:
var compose = function () {
var funcs = arguments;
return function () {
var args = arguments;
for (var i = funcs.length; i-- > 0;) {
args = [funcs[i].apply(this, args)];
}
return args[0];
};
};
Then I do a composition:
var composedFunction = compose(func1, func2, ..., funcn)
Which run from the right to left and all works just fine.
You lineparser seems to have methods like formatSpaces, capitalize and formatSomethingElse. The easiest thing you could do is to make all those methods to return this, so that you can chain those methods like so:
var outputline = LineParser.formatSpaces(inputLine).capitalize().formatSomethingElse()
Though by the looks of it, all of the methods require some string as a parameter, so you might have to make some implementation changes such as saving the string in a private variable if given and pullin it from the variable if no parameters are given.
Remark about your Edit. The function compose is very functional in the principle but not in its implementation. Indeed, the function mutates some variables (e.g., i and args) and is therefore not fully functional.
To avoid using these mutating variables, you could possibly define compose recursively. Another solution ould be to rely on third-party functional library, such as underscore-js for example (http://underscorejs.org/), which already defines a composition function.
Additional (obvious) remark: to make your code functional with compose, the functions func1, func2,... that are composed, should not mutate their arguments.
If you want asynchronous programming but you don't like nested callbacks, have you considered the async lib ?
You could have something like this :
var LineParser = require('../modules/LineParser');
var inputLine = 'A line with multiple spaces';
async.waterfall([
function(callback) {
var result = LineParser().formatSpaces(inputLine);
callback(null, result);
},
function(arg1, callback) {
var result = LineParser().capitalize(arg1);
callback(null, result);
},
function(arg1, callback) {
var result = LineParser().formatSomethingElse(arg1);
callback(null, result);
}
], function (err, result) {
// retrieve the final string
});
which can be turned into something useful if you modify your LineParser methods into asynchronous methods (otherwise it will only make your 3 lines heavier)
Functional style, that is, pure functional style that we see in Lisp etc. looks like this:
var outputline = formatSomethingElse(capitalize(formatSpaces(inputline)));
Often, for readability it would be formatted as:
var outputline = formatSomethingElse(
capitalize(
formatSpaces(inputline)
)
);
Any other form is not functional style. Functional style are a bit like Reverse Polish Notation in that the stated operation should be read in reverse. Indeed, RPN is itself a functional programming syntax (as embodied by Forth).
There is a style that has a similar look and feel to the functional style: method chaining:
var outputline = LineParser(inputline)
.formatSpaces()
.capitalize()
.formatSomethingElse()
.toString();
Unlike functional style, method chaining is read in order.
While the most famous chaining library, jQuery, mutates the state of the object it's not really necessary to do that. Take for example the following simple implementation of LineParser:
function LineParser (text) {
return {
text: text,
toString: function () {return this.text},
capitalize: function () {
// return a new object instead of "this"
return {
text : _capitalize(this.text),
toString : this.toString
}
}
}
}