I wanted to make a compose function for piping and im stuck. I managed to make a pointfree pipe but cant figure out composing.
// pointfree
const pipe = fn => future => future.pipe(fn)
// compose pipes // not working
const composePipe = (...fns) => (...args) => fns.reduceRight( (future, fn) => future.pipe(fn), args)[0];
I'll answer your question eventually, but let's take a step back first.
An important thing to understand is that the pipe method is just function application. In other terms: future.pipe (f) == f (future).
This means that your pipe function can be redefined as such:
const pipe = fn => future => future.pipe(fn)
//to:
const pipe = fn => value => fn (value)
This new version of pipe works exactly the same way, except that it works on any values, not just Futures. But let's take a step back further even.
The signature of this function is as follows: pipe :: (a -> b) -> a -> b. It takes a function from A to B, and returns a function from A to B.
Wait a minute....
const pipe = fn => value => fn (value)
//to:
const pipe = fn => fn
That new definition does the same thing. Except that it works on anything, not just Functions. Actually it's just the identity function. So a curried (you said point-free, but I think you meant curried) version of future.pipe is just the identity function.
So why is this? Because all .pipe does is function application. And you can apply your functions yourself.
Now to answer your next question about composing pipes. What you're actually looking for is something that takes a number of functions, and applies them in sequence.
If you're using Ramda, that's pipe. We can implement this ourselves though:
const pipe = (...fns) => (...args) => fns.reduce ((args, f) => [f (...args)], args)[0]
I'm using Ramda in node with express. I have a standard route:
app.get('/api/v1/tours', (req, res) => {
}
Where I'd like to compose functions using Ramda, but I write these functions outside the route (so they will be reusable in other routes).
For example:
function extractParams() {
return req.query.id;
}
function findXById(id) {
return xs.find(el => el.id == id);
}
function success(answer) {
return res.status(200).json(answer);
}
Now I want to compose those functions inside several routers. One of them will be:
app.get('/api/v1/tours', (req, res) => {
return R.pipe(extractParams, findXById, success)();
}
Is there any way I can prepare a generic wrapper that wraps the request and response objects on the routers to be available to these functions? I guess I'll
also have to change their signature.
I think what's really needed here is a version of pipe that accepts some initial arguments and returns a new function that will accept the remaining ones, with all the functions having such a dual-application signature. I came up with the following doublePipe implementation that does this:
const doublePipe = (...fns) => (...initialArgs) =>
pipe (...(map (pipe (apply, applyTo (initialArgs)), fns) ))
const foo = (x, y) => (z) => (x + y) * z
const bar = (x, y) => (z) => (x + y) * (z + 1)
const baz = doublePipe (foo, bar)
console .log (
baz (2, 4) (1) //=> (2 + 4) * (((2 + 4) * 1) + 1) => 42
// / \ '------+----'
// bar ( x --/ , `-- y , `-- z, which is foo (2, 4) (1) )
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {pipe, map, apply, applyTo} = R </script>
Note that the functions foo and bar will both receive the same x and y arguments, and that foo (x, y) will receive the z argument supplied from the outside, with its result passed as z to bar (x, y).
This is an interesting function, and it's a fairly useful generic solution to this sort of problem. But it won't work in your Express environment, because the handlers need to have the signature (req, res) => ... and not (req, res) => (...args) => ....
So below is an alternative, which mimics a trivial Express-like environment and uses a slightly different doublePipe version, which does not take an additional invocation, simply calling the first function with no parameters, and then sequentially passing the results through to the others as expected. This means the first function to doublePipe must have the signature (req, res) => () => ..., while the others have (req, res) => (val) => .... While we could fix it so that that the first one was just (req, res) => ..., it seems to me that this inconsistency would not be helpful.
const doublePipe = (...fns) => (...initialArgs) =>
reduce (applyTo, void 0, map (apply (__, initialArgs), fns))
const xs = [{id: 1, val: 'abc'}, {id: 2, val: 'def'},{id: 3, val: 'ghi'}, {id: 4, val: 'jkl'}]
const extractParams = (req, res) => () => req .query .id
const findXById = (xs) => (req, res) => (id) => xs .find (el => el .id == id)
const success = (req, res) => (answer) => res .status (200) .json (answer)
app .get ('/api/v1/tours', doublePipe (extractParams, findXById (xs), success))
console .log (
app .invoke ('get', '/api/v1/tours?foo=bar&id=3')
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>
const {__, map, reduce, applyTo, apply, head, compose, split, objOf, fromPairs, last} = R
// Minimal version of Express, only enough for this demo
const base = compose (head, split ('?'))
const makeRequest = compose (objOf ('query'), fromPairs, map (split ('=')), split ('&'), last, split ('?'))
const makeResponse = () => {
const response = {
status: (val) => {response .status = val; return response},
json: (val) => {response.body = JSON .stringify (val); delete response.json; return response}
}
return response
}
const app = {
handlers: {get: {}, post: {}},
get: (route, handler) => app .handlers .get [route] = handler,
invoke: (method, route) =>
app .handlers [method] [base (route)] (makeRequest (route), makeResponse ())
}
</script>
findById does not have the required signature, but findById(xs) does, so that's what we pass into pipe.
Finally, note that Ramda and Express may never play particularly well together, as the handlers sent to Express are meant to modify their parameters, and Ramda is designed to never mutate input data. That said, this seems to work reasonably well for these requirements.
Update: explanation of doublePipe
A comment seemed to indicate that a more complete description of doublePipe was in order. I will only discuss the second version,
const doublePipe = (...fns) => (...initialArgs) =>
reduce (applyTo, void 0, map (apply (__, initialArgs), fns))
Here are two possible calls:
// foo :: (a, b) -> f
const foo = doublePipe (
f1, // :: (a, b) -> Void -> (c)
f2, // :: (a, b) -> c -> d
f3, // :: (a, b) -> d -> e
f4, // :: (a, b) -> e -> f
)
// bar :: (a, b, c) -> f
const bar = doublePipe (
g1, // :: (a, b, c) -> Void -> d
g2, // :: (a, b, c) -> d -> e
g3, // :: (a, b, c) -> e -> f
)
If you're not familiar with the Hindley-Milner signatures (such as (a, b) -> c -> d above), I wrote a long article on the Ramda wiki about their uses in Ramda. The foo function is built by passing f1 - f4 to doublePipe. The resulting function takes parameters of types a and b (req and res in your example) and returns a value of type f. Similarly bar is created by supplying g1 - g3 to doublePipe, returning a function that accepts parameters of types a, b, and c and returning a value of type f.
We can rewrite doublePipe a bit more imperatively to show the steps taken:
const doublePipe = (...fns) => (...initialArgs) => {
const resultFns = map (apply (__, initialArgs), fns)
return reduce (applyTo, void 0, resultFns)
}
and expanding that a bit, this might also look like
const doublePipe = (...fns) => (...initialArgs) => {
const resultFns = map (fn => fn(...initialArgs), fns)
return reduce ((value, fn) => fn (value), undefined, resultFns)
}
In the first line, we partially apply the initial arguments to each of the supplied functions, giving us a list of simpler functions. For foo resultFns would look like [f1(req, res), f2(req, res), f3(req, res), f4(req, res)], which would have signatures [Void -> c, c -> d, d -> e, e -> f]. We could now choose to pipe those functions and call the resulting function (return pipe(...resultFns)()), but I didn't see a good reason to create the piped function only to call it a single time and throw it away, so I reduce over that list, starting with undefined and passing the result of each one to the next.
I tend to think in terms of Ramda functions, but you could write this easily enough without them:
const doublePipe = (...fns) => (...initialArgs) =>
fns
.map (fn => fn (...initialArgs))
.reduce ((value, fn) => fn (value), void 0)
I hope this made that clearer!
Your three functions do not have the things they need in their declared scope. You need to modify their signature first:
function extractParams(req) { //<-- added `req`
return req.query.id;
}
function findXById(id, xs) { //<-- added `xs`
return xs.find(el => el.id == id);
}
function success(res, answer) { //<-- added `res`
return res.status(200).json(answer);
}
Note that the order of the parameters isn't "random". The data you need to operate on should be the last as it allows for a nicer function composition experience. It's one of the tenet of Ramda:
The parameters to Ramda functions are arranged to make it convenient for currying. The data to be operated on is generally supplied last.
Source: https://ramdajs.com/
This is not enough though. You need to curry some of them. Why? While the "recipe" of your function composition looks the same, each individual function operate on a specific data. This will make sense later, let's curry first:
const extractParams = (req) => req.query.id;
const findXById = R.curry((id, xs) => xs.find(el => el.id == id));
const success = R.curry((res, answer) => res.status(200).json(answer));
Now you can build a function composition whilst supplying some specific parameter to your functions in the composition:
app.get('/api/v1/tours', (req, res) =>
R.pipe(
extractParams,
findXById(42),
success(res))
(req));
It's important to note that while there is nothing "wrong" with this, it's also missing the point:
R.pipe(extractParams, findXById, success)()
Why? R.pipe or R.compose (or R.o) returns a function composition which is itself a function that you call with parameters (just one with R.o but let's ignore that for now). So you need to think about the data that goes through your function composition. In your case it's probably req:
R.pipe(extractParams, findXById, success)(req)
Each function in your function composition receives as its parameter, the result of the previous function. If something in between doesn't depend on that, then perhaps that function shouldn't be part of the composition. (Take that advice with a pinch of salt; special conditions may apply; just think about it ;)
I am still new to functional programming and have been trying to learn how to use transducers. I thought I had a good use case but every time I attempt to write a transducer with Ramda for it, I get the following error:
reduce: list must be array or iterable
I have tried rewriting it several ways and looked at several explanations on the web of transduction but to no avail. Any suggestions?
const data = [{cost:2,quantity:3},{cost:4,quantity:5},{cost:1,quantity:1}];
const transducer = R.compose(R.map(R.product), R.map(R.props(['cost', 'quantity'])));
const result = R.transduce(transducer, R.add, 0)(data);
console.log(result)
In the context of a transducer, compose reads left to right. You just need to invert product and props:
const data = [
{cost:2,quantity:3},
{cost:4,quantity:5},
{cost:1,quantity:1}];
const transducer =
compose(
map(props(['cost', 'quantity'])),
map(product));
console.log(
transduce(transducer, add, 0, data)
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {compose, map, props, product, transduce, add} = R;</script>
The reason why the order reverses is that transducers utilize a property of function composition that is sometimes called abstraction from arity. It simply means that a function composition can return, well, another function:
const comp = f => g => x => f(g(x));
const mapTrace = tag => f => (console.log(tag), xs => (console.log(tag), xs.map(f)));
const sqr = x => x * x;
const main = comp(mapTrace("a")) (mapTrace("b")) (sqr); // returns another function
console.log(main); // logs the 2nd map and then the 1st one (normal order)
// pass an additional argument to that function
console.log(
main([[1,2,3]])); // logs in reverse order
Why returns the composition another function? Because map is a binary function that expects a function argument as its first argument. So when the composition is evaluated it yields another compositon of two partially applied maps. It is this additional iteration that reverses the order. I stop at this point without illustrating the evaluation steps, because I think it would get too complicated otherwise.
Additionally, you can see now how transducers fuse two iterations together: They simply use function composition. Can you do this by hand? Yes, you can absolutely do that.
What if we define a |>! operator like so:
let (|>!) a f = async {
let! r = a
return f r
}
Then instead of writing
let! r = fetchAsync()
work r
we could write
fetchAsync() |>! work
Is this a good idea or would it generate inefficient code?
The |>! operator you're describing is the standard "map" pattern that can apply to just about any "wrapper" type, not just async. If your return f r had been return! f r then you would have the standard "bind" pattern, which by convention should be written as the operator >>= if you're defining an operator for it.
And it is a good idea, but with one minor change. You've written it with the async value as the first parameter and the function as the second parameter, but the way you used it, fetchAsync() |>! work, requires the function to be the first parameter, e.g. let (|>!) f a = .... (If you look at the way Scott Wlaschin implements this in the first example I linked, he puts the function as the first parameter as well.) Also, I think most F# programmers would choose not to write this as an operator, but as a function called Async.map, so that its usage would look like this:
let result =
fetchAsync()
|> Async.map step1
|> Async.map step2
|> Async.map step3
(Really strugging to title this question, so if anyone has suggestions feel free.)
Say I wanted to do an operation like:
take an array [1,2,3]
multiply each element by 2 (map): [2,4,6]
add the elements together (reduce): 12
multiply the result by 10: 120
I can do this pretty cleanly in underscore using chaining, like so:
arr = [1,2,3]
map = (el) -> 2*el
reduce = (s,n) -> s+n
out = (r) -> 10*r
reduced = _.chain(arr).map(map).reduce(reduce).value()
result = out(reduced)
However, it would be even nicer if I could chain the 'out' method too, like this:
result = _.chain(arr).map(map).reduce(reduce).out(out).value()
Now this would be a fairly simple addition to a library like underscore. But my questions are:
Does this 'out' method have a name in functional programming?
Does this already exist in underscore (tap comes close, but not quite).
This question got me quite hooked. Here are some of my thoughts.
It feels like using underscore.js in 'chain() mode' breaks away from functional programming paradigm. Basically, instead of calling functions on functions, you're calling methods of an instance of a wrapper object in an OOP way.
I am using underscore's chain() myself here and there, but this question made me think. What if it's better to simply create more meaningful functions that can then be called in a sequence without having to use chain() at all. Your example would then look something like this:
arr = [1,2,3]
double = (arr) -> _.map(arr, (el) -> 2 * el)
sum = (arr) -> _.reduce(arr, (s, n) -> s + n)
out = (r) -> 10 * r
result = out sum double arr
# probably a less ambiguous way to do it would be
result = out(sum(double arr))
Looking at real functional programming languages (as in .. much more functional than JavaScript), it seems you could do exactly the same thing there in an even simpler manner. Here is the same program written in Standard ML. Notice how calling map with only one argument returns another function. There is no need to wrap this map in another function like we did in JavaScript.
val arr = [1,2,3];
val double = map (fn x => 2*x);
val sum = foldl (fn (a,b) => a+b) 0;
val out = fn r => 10*r;
val result = out(sum(double arr))
Standard ML also lets you create operators which means we can make a little 'chain' operator that can be used to call those functions in a more intuitive order.
infix 1 |>;
fun x |> f = f x;
val result = arr |> double |> sum |> out
I also think that this underscore.js chaining has something similar to monads in functional programming, but I don't know much about those. Though, I have feeling that this kind of data manipulation pipeline is not something you would typically use monads for.
I hope someone with more functional programming experience can chip in and correct me if I'm wrong on any of the points above.
UPDATE
Getting slightly off topic, but one way to creating partial functions could be the following:
// extend underscore with partialr function
_.mixin({
partialr: function (fn, context) {
var args = Array.prototype.slice.call(arguments, 2);
return function () {
return fn.apply(context, Array.prototype.slice.call(arguments).concat(args));
};
}
});
This function can now be used to create a partial function from any underscore function, because most of them take the input data as the first argument. For example, the sum function can now be created like
var sum = _.partialr(_.reduce, this, function (s, n) { return s + n; });
sum([1,2,3]);
I still prefer arr |> double |> sum |> out over out(sum(double(arr))) though. Underscore's chain() is nice in that it reads in a more natural order.
In terms of the name you are looking for, I think what you are trying to do is just a form of function application: you have an underscore object and you want to apply a function to its value. In underscore, you can define it like this:
_.mixin({
app: function(v, f) { return f (v); }
});
then you can pretty much do what you asked for:
var arr = [1,2,3];
function m(el) { return 2*el; };
function r(s,n) { return s+n; };
function out(r) { return 10*r; };
console.log("result: " + _.chain(arr).map(m).reduce(r).app(out).value()));
Having said all that, I think using traditional typed functional languages like SML make this kind of think a lot slicker and give much lighter weight syntax for function composition. Underscore is doing a kind of jquery twist on functional programming that I'm not sure what I think of; but without static-type checking it is frustratingly easy to make errors!