Better way to compose nested functions - javascript

Suppose I have two functions with the following types.
f :: (a, b) -> c
g :: (a, b, c) -> d
I can compose them as follows.
function h(a, b) {
const c = f(a, b);
const d = g(a, b, c);
return d;
}
Here, h is a composition of g and f. However, this looks a lot like imperative code with the constant declarations and the return statement. How can I compose any two such functions in a functional style?

You can define h in a single line as follows.
const h = (a, b) => g(a, b, f(a, b));
Then you can generalize this composition for all such functions as follows.
const ss = (g, f) => (a, b) => g(a, b, f(a, b));
const h = ss(g, f);
This is actually the same as the S combinator but extended to two inputs. Hence, the name ss.
Alternatively, we could generalize the S combinator to any number of inputs using the spread operator as Scott Sauyet suggested.
const s = (g, f) => (...args) => g(...args, f(...args));
const h = s(g, f);
Personally, I'd stay away from polyvariadic functions.
By the way, you original example is not imperative even though it uses constant declarations.

This looks like a problem of how to combine two functions in a somewhat different way than by simple composition. We can write combinators that do this for us.
In this case, we essentially want to use our initial a and b arguments in f to generate d and use a, b, and d in g. We can write a function that combines arbitrary f and g to do this, keeping our original arguments and adding an additional one in the call to g. Maybe we'd call it addArg:
const addArg = (g, f) => (...args) =>
g (...args, f (...args))
This version attempts to be a bit more generic; we don't handle only two parameters. We can have any number of arguments to f, and we add one more to the call to g.
Here is a quick demo:
const addArg = (g, f) => (...args) =>
g (...args, f (...args))
const f = (a, b) => `f (${a}, ${b})`
const g = (a, b, d) => `g (${a}, ${b}, ${d})`
const h = addArg (g, f)
console .log (h ('a', 'b'))

I don't think there is anything wrong with the previous answers but I wanted to add an alternative and also to warn you about combinators.
I feel uncomfortable with the use of custom combinators because the reader must look up their definition, which reduces the value of using them.
I am familiar with lift2 and my first instinct would be to bend it to apply it to your pattern (your functions must be curried for it to work)
const lift2 = f => g => h => x => f (g (x)) (h (x));
const id = x => x;
const h = (a, b) => lift2 (g (a)) (id) (f (a)) (b);
So we're partially applying f and g with a and using id to store b until it's fed to g.
If you have trouble parsing the above, we can express lift2 like so, to make it more clear what is happening:
const lift2 = ga => id => fa => b => ga (id (b)) (fa (b));
Honestly I would go for the first one-liner suggested by Aadit M Shah, or for the second one, but named h, to sort of convey "it's just the h you would expect, but with dependencies injected"... or your implementation. Yours even provides explanatory variable names. I mean why not!
Even known combinators sometimes only obfuscate intent. It all depends with whom you work. And that includes your future self ;)

Related

Is it possible to compose two functions of the same signature, but with differeing inputs/outputs?

Basically, my problem comes down to composing the functionality of several functions of this signature:
(a: A, b: B) => c: C
To simplify, I need to do something like this, where each of a, b, and c are different types:
const upper = (a, b) => {
const c = a.toString().toUpperCase();
return c;
}
const pad = (a, b) => {
const c = a.toString().padStart(2, '0');
return c;
}
const repeat = (a, b) => {
const c = a.toString().repeat(2);
return c;
}
const format = compose(repeat, pad, upper);
For the record b is used, I'm just omitting it here for simplicity, but assume it must be provided to each function, and each will receive the same value as an argument.
So far, I've been able to solve for the issue of (a, b) => c not being composable due to the number of arguments by currying the functions, flipping the params, and partially applying b to each before I compose them:
I'm using standard compose and flip utilities like so: https://medium.com/javascript-scene/curry-and-function-composition-2c208d774983
const compose = (...fns) => x => fns.reduceRight((y, f) => f(y), x);
const flip = fn => a => b => fn(b)(a);
const fnArr = [
repeat,
pad,
upper
];
const makeFormatter = functionArray => (a, b) => {
const flippedAndPartiallyApplied = functionArray.map(fn =>
flip(curry(fn))(b)
);
return compose(...flippedAndPartiallyApplied)(a);
};
const formatter = makeFormatter(fnArr);
So with this, I've gotten the whole b issue out of the way, and I can compose several unary functions. But my issue remains that each of my functions are a => c.
Notice how each of my functions must call .toString(). I need this step before I can modify and return my value. Unfortunately, I need to keep true to each function keeping that same signature.
Is there any way I can further modify each function programatically in a way that I don't need to modify the function source codes, but can mutate them in a way that fits my composition pipeline, or is this just not possible?
I'm working with a API that runs calendar days through a function you provide to the API that can be used to render a day cell to a datepicker UI. This is the API for reference, and this is an example.
I have a use case where I could have multiple renderDay functions provided through various sources in my app. I'd like to combine these functions somehow because the API only accepts one, and I'd like to do it in an elegant way.
If you have a list of (a, b) -> c and need to bring that back to just one function of (a, b) -> c, I think you can rephrase the problem to defining [c] -> c.
For example:
const formatter1 = (a, b) => a.toUpperCase();
const formatter2 = (a, b) => `${a}-${a}`;
const formatters = [formatter1, formatter2];
// Generic combiner of formatters
const applyAll = fs => (a, b) => fs.map(f => f(a, b));
// Reducer logic
const takeFirst = cs => cs[0];
const concat = cs => cs.reduce(
(acc, c) => acc + c + "\n", "");
const takeLongest = cs => cs.reduce(
(acc, c) => acc.length > c.length ? acc : c, "" );
// Construct a formatter by composing applyAll and a reducer
const compose = (f, g) => (...args) => f(g(...args));
const formatterA = compose(takeFirst, applyAll(formatters));
const formatterB = compose(concat, applyAll(formatters));
const formatterC = compose(takeLongest, applyAll(formatters));
console.log("Take first:\n", formatterA("a", "b"));
console.log("Concat:\n", formatterB("a", "b"));
console.log("Take longest:\n", formatterC("a", "b"));
What you essentially have to define is how to combine the Elements that are produced by the different formatters.
There is not one right answer to this question. The most straight forward answer would be to concatenate the elements:
const dayFormatter = (date, opts) => (
<>
{allFormatters.map(f => f(date, opts))}
</>
)
How about equipping the different renderDay-functions with an additional predicate that tells whether it isApplicable to a given day or not, and then going through the list of such DayRenderers, and selecting the first that is applicable?
type DayRenderer = (d: Date, mod: DayModifiers) => React.ReactNode
type DayRendererSelector = {
isApplicable: (d: Date, modifiers: DayModifiers) => boolean,
renderDay: DayRenderer
};
function combineDayRenderers(
cases: DayRendererSelector[],
defaultRenderer: DayRenderer
): DayRenderer {
return (d: Date, mod: DayModifiers) => {
for (const { isApplicable, renderDay } of cases) {
if (isApplicable(d, mod)) {
return renderDay(d, mod);
}
}
return defaultRenderer(d, mod);
}
}
If I had to name that "pattern", it would be "vertical composition of partial functions" (something like what's being discussed here). It's basically the same as
a switch { case ... case ... case ... default: ... }, but with a list of cases.

What is the binary operator of Function Monoids in example of JavaScript

In this article Function Monoids are introduced with C# code and Haskell Type definition.
A function a -> b is a monoid if b is a monoid. This means that
you can combine two functions with the same type. In an
object-oriented context, it means that you can combine two methods
with the same signature into one method as long as the return type
forms a monoid.
Generalisation
While the above C# code is only an example, the general rule is that
any function that returns a monoid is itself a monoid. In Haskell,
this rule is articulated in the standard library:
instance Monoid b => Monoid (a -> b)
This means that for any monoid b, a function a -> b is also
(automatically) a monoid.
The problem is the example in C# is too specific about "GUID" and I have no idea what the author trying to do in the code, and the Haskell Type Definition is merely the type definition.
What is an example code in JavaScript to implement this Function Monoids?
cf)
Why is instance Monoid b => Monoid (a -> b) in base?
Monoid Laws
identity law:
combine (identity, a) == combine (a, identity)
associativity law:
combine (a, combine (b, c)) == combine (combine (a, b), c)
We can implement an identity element (identity) and binary operation (combine) for functions -
// identity element
const identity =
x => x
// binary operation
const combine = (a, b) =>
x => a (b (x))
// sample functions
const a =
x => x + 3
const b =
x => x - 1
const c =
x => x * x
// uphold laws
console.log
( combine (identity, a) (2) === combine (a, identity) (2)
, combine (a, combine (b, c)) (2) === combine (combine (a, b), c) (2)
)
// => true
// => true
The binary operation and identity element is different depending on your domain. See the table on Wikipedia for more insight on how to implement the identity element and binary operation for various sets.
Of course you are not limited to those domains. Your custom type may have various binary operations and identity elements that satisfy the monoid laws. If the laws are upheld, your type belongs to the monoid category.
It's important to know that being able to combine things doesn't necessarily mean they are a monoid. For something to be a Monoid, it must have associativity, left identity, and right identity.
C#:
public static Func<Guid, int> Combine(
Func<Guid, int> f,
Func<Guid, int> g)
{
return x => f(x) + g(x);
}
JS:
function combine(f,g) {
return x => f(x) + g(x)
}
function addOne(x) {
return x + 1;
}
function addTwo(x) {
return x + 2;
}
let newFunction = combine(addOne, addTwo);
let result = newFunction(0);
console.log(result)

How to write a composed function using Ramda compose?

How to modify the zComposedFn function so that the output of both z and zComposedOutput is same?
const R = require('ramda');
let f1 = R.curry((p1, p2, p3) => {
let result = {
n1: p1,
n2: p2,
n3: p3
};
return result;
}
);
let x = f1(1, 2, 3);
let y = f1(1, 2, x);
let z = f1(1, x , y);
console.log(z);
let zComposedFn = R.compose(f1);
let input = [1,2,3];
let zComposedOutput = zComposedFn(...input);
console.log(zComposedOutput);
The goal is to create some metric calculation functions having the same signature and output type but different implementation.
const MetricFn = (m,f,a) => {<to be implemented using switch case on m> return b}
m : name of metric as string
f : Array of functions utilizing input data objects
a : input data object
example:
There is a financial dashboard, which receives the input data as (1,2,3). The dashboard displays the metric1, metric2 and metric3 calculated as below:
metric1 = MetricFn('metric1',[f1])(1,2,3);
metric2 = MetricFn('metric2',[f1, f2])(1,2,3);
metric3 = MetricFn('metric3',[f1, f2, f3])(1,2,3);
I am wondering on how to create the structure of MetricFn.
I can make very little sense out of your function. And I don't see anything that Ramda offers to help. While I'm a Ramda author, I don't always recall every function, but it seems unlikely.
Your requirements looks vaguely like the use of chain with functions, where chain(f, g) ~~> x => f(g(x))(x). But it's only a vague connection, and I can't see how to use chain to do what you are trying to do.
Is there an underlying problem you're trying to solve that we might be able to help with?
Here is a trivial implementation, but it's mostly just restating your code without the intermediate variables:
const foo = curry((f, a, b, c) => f(a, f(a, b, c), f(a, b, f(a, b, c))))
foo(f1)(1, 2, 3)

Using the same first argument in a Ramda pipe

Is it possible to compose the following function in Ramda?
(a, b) => R.pipe(func1(a), func2(a))(b)
The aim is passing argument a to all functions in the pipe.
My initial thought was the following:
R.pipe(R.juxt([func1, func2]), R.apply(R.pipe))
But this gives TypeError: Cannot read property 'length' of undefined.
This is easier to express using S.pipe as it takes an array of functions to compose.
One option is to use R.ap:
> S.pipe(R.ap([S.add, S.mult, S.add], [3]), 10)
42
Another option is to use R.map with S.T, the thrush combinator:
> S.pipe(R.map(S.T(3), [S.add, S.mult, S.add]), 10)
42
You could then wrap one of these in a lambda to create a binary function:
const f = (a, b) => S.pipe(R.ap([S.add, S.mult, S.add], [a]), b);
f(3, 10); // add(3)(mult(3)(add(3)(10)))
// => 42
You have to create a curried version of all the functions, then call the curried version of each with a and finally use b in either R.pipe or R.reduce
Let's say that the functions that need to have a as the first argument are f,g,h (in that specific order) then we want to achieve the following expression
h(a, g(a, f(a, b)))
First of all let's create a curried function which receives two arguments, a single value v and a function fn, when this function receives all its required arguments it will simply return fn(v)
const rev = R.curry((v, fn) => fn(v))
Next we can create the curried versions of the functions with R.map and R.curry
// note the reversed order of the functions
// I'll use R.compose instead of R.pipe
let curriedVersion = R.map(R.curry, [h,g,f])
However we also need to use a as the first argument of the curried functions, we could call each curried function with a using R.map but instead we will use our special function rev
const curriedVersion = R.map(R.compose(rev(a), R.curry), [h,g,f])
Finally let's use this array of curried functions with R.compose and b
const result = R.compose.apply(undefined, curriedVersion)(b)
One liner (for the functions f,g,h in that specific order):
const solver = (a, b) => R.compose.apply(undefined, R.map(R.compose(rev(a), R.curry), [h,g,f]))(b)
const add = (a, b) => a + b
const sub = (a, b) => a - b
const mul = (a, b) => a * b
const rev = R.curry((v, fn) => fn(v))
const solver = (a, b) => R.compose.apply(undefined, R.map(R.compose(rev(a), R.curry), [mul,sub,add]))(b)
// mul(2, sub(2, add(2, 3)))
// mul(2, sub(2, 5))
// mul(2, -3)
// -6
console.log(solver(2, 3))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.21.0/ramda.min.js"></script>

Is it possible to define an infix function?

Is it possible to define my own infix function/operator in CoffeeScript (or in pure JavaScript)? e.g. I want to call
a foo b
or
a `foo` b
instead of
a.foo b
or, when foo is global function,
foo a, b
Is there any way to do this?
ES6 enables a very Haskell/Lambda calculus way of doing things.
Given a multiplication function:
const multiply = a => b => (a * b)
You can define a doubling function using partial application (you leave out one parameter):
const double = multiply (2)
And you can compose the double function with itself, creating a quadruple function:
const compose = (f, g) => x => f(g(x))
const quadruple = compose (double, double)
But indeed, what if you would prefer an infix notation? As Steve Ladavich noted, you do need to extend a prototype.
But I think it can be done a bit more elegant using array notation instead of dot notation.
Lets use the official symbol for function composition "∘":
Function.prototype['∘'] = function(f){
return x => this(f(x))
}
const multiply = a => b => (a * b)
const double = multiply (2)
const doublethreetimes = (double) ['∘'] (double) ['∘'] (double)
console.log(doublethreetimes(3));
Actually adding this as an answer: no, this is not possible.
It's not possible in vanilla JS.
It's not possible in CoffeeScript.
You can with sweet.js. See:
http://sweetjs.org/doc/main/sweet.html#infix-macros
http://sweetjs.org/doc/main/sweet.html#custom-operators
Sweet.js extends Javascript with macros.
It acts like a preprocessor.
This is definitely not infix notation but it's kinda close : /
let plus = function(a,b){return a+b};
let a = 3;
let b = 5;
let c = a._(plus).b // 8
I don't think anyone would actually want to use this "notation" since it's pretty ugly, but I think there are probably some tweaks that can be made to make it look different or nicer (possibly using this answer here to "call a function" without parentheses).
Infix function
// Add to prototype so that it's always there for you
Object.prototype._ = function(binaryOperator){
// The first operand is captured in the this keyword
let operand1 = this;
// Use a proxy to capture the second operand with "get"
// Note that the first operand and the applied function
// are stored in the get function's closure, since operand2
// is just a string, for eval(operand2) to be in scope,
// the value for operand2 must be defined globally
return new Proxy({},{
get: function(obj, operand2){
return binaryOperator(operand1, eval(operand2))
}
})
}
Also note that the second operand is passed as a string and evaluated with eval to get its value. Because of this, I think the code will break anytime the value of operand (aka "b") is not defined globally.
Javascript doesn't include an infix notation for functions or sections for partial application. But it ships with higher order functions, which allow us to do almost everything:
// applicator for infix notation
const $ = (x, f, y) => f(x) (y);
// for left section
const $_ = (x, f) => f(x);
// for right section
const _$ = (f, y) => x => f(x) (y);
// non-commutative operator function
const sub = x => y => x - y;
// application
console.log(
$(2, sub, 3), // -1
$_(2, sub) (3), // -1
_$(sub, 3) (2) // -1
);
As you can see I prefer visual names $, $_ and _$ to textual ones in this case. This is the best you can get - at least with pure Javascript/ES2015.
You can get close by function currying:
const $ = (a) => (f) => f(a);
const plus = (a) => (b) => (a+b);
const twoPlusThree = $ (2) (plus) (3);
But I still haven't figured out a neat way to compose this construction.

Categories

Resources