I stumbled upon this javascript statement:
const pipe = (...fns) => x => fns.reduce((y, f) => f(y), x);
I don't understand the expression f(y), x. With some experimenting I found out that this is working too: f(y(x)). It gives the exact same result (for my example at least and is much more understandable to me).
const pipe1 = (...fns) => x => fns.reduce((y, f) => f(y), x);
const pipe2 = (...fns) => x => fns.reduce((y, f) => f(y(x)));
const addThree = x => x + 3;
const addTwo = x => x + 2;
let x1 = pipe1(addTwo, addThree)(2); //x1 is seven
let x2 = pipe2(addTwo, addThree)(2); //x2 is seven
Then I thought that this is some syntax sugar for x,y for x(y) and tried this:
let z = n => addThree, n; //addThree(n)? no, that does not work!
I need some light on the expression f(y), x). Yes I read some stackoverflow articles that the expression is evaluated form left to right and the last is returned. It just makes no sense to me in this example.
fns.reduce((y, f) => f(y), x)
If you format it, it might make more sense.
fns.reduce(
(y, f) => f(y),
x
)
So (y, f) => f(y) is the first parameter to reduce (the reducer function), and x is the 2nd parameter to reduce, which is the initial value.
In conclusion, you were thrown off by the lack of grouping with the arrow function. :)
"Value-X" is going to be the x variable, passed as the 2nd parameter to the reduce function.
const pipe = (...fns) => x => fns.reduce((y, f) => f(y), x);
const foo = pipe(func1, func2, func3);
foo("Value-X");
The expression can be rewritten as this, if it helps to clarify things:
function pipe(...fns) {
return function (x) {
function chain(y, f) {
// y = previous return value
// If this is the first time the function is called, y = x
return f(y);
}
return fns.reduce(chain, x);
}
}
const x = (a) => b(a) is the same thing as const x = b
const a = () => { console.log('hi'); }
let x1 = a;
let x2 = () => a();
x1();
x2();
Whats the difference between..
const equalField = R.propEq('field'); // NOT WORK!
and
const equalField = (f) => R.propEq('field')(f); // WORKS!
The first one return a function, the second one return the result.
Check my code snippet...
const addingError = {
message: '',
errors: [ { field: "number" }, { field: "mac" } ]
}
// const equalField = R.propEq('field'); // NOT WORK!
const equalField = (f) => R.propEq('field')(f); // WORKS!
const getErrors = R.pipe(R.always(addingError), R.prop('errors'))
const anyField = R.converge(R.any, [equalField, getErrors])
const result = anyField('mac');
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.23.0/ramda.js"></script>
My intention is...
When I call anyField('mac')
R.any will be called with R.any(equalField('mac'), getErrors('mac'))
equalField('mac') returns a function, and this is ok because the first argument of R.any is a function
getErrors('mac') returns a array, and this is ok because the second argument of R.any is an array.
It all depends on b …
x = (a) => b(a) is not the same thing as x = b
You are wrong if b is a function that expects exactly 1 argument – or b is a curried function
You are right if b is a function that expects more than 1 argument
The problem is compounded because Ramda has a magical API that allows you to interact with a single function as if it was curried or uncurried.
// Ramda magic
R.propEq('a', 'b', {a: 'b'}) // true
R.propEq('a')('b', {a: 'b'}) // true
R.propEq('a', 'b')({a: 'b'}) // true
R.propEq('a')('b')({a: 'b'}) // true
This is going to generate some confusion (and I personally think this sucks), but we're going to ignore it for now
Simplified demonstrations
Below: b is a function that expects exactly 1 argument. x and y work as intended
const b = n => n + 1
const x = b
const y = n => b (n)
console.log(x(1)) // 2
console.log(y(1)) // 2
Below: b is a function that expects more than 1 argument – y is a problem in this case
const b = (n,m) => n + m
const x = b
const y = n => b(n)
console.log(x(1,2)) // 3
console.log(y(1,2)) // NaN
Below: b is a curried function that expects more than 1 argument – y is no longer a problem
const b = n => m => n + m
const x = b
const y = n => b(n)
console.log(x(1)(2)) // 3
console.log(y(1)(2)) // 3
Ramda magic sauce; source of confusion
So regarding Ramda specifically, the answer is slightly more complicated
Below, if we call x and y in curried form, we get exactly the answer we are expecting – however, if we call x and y with both remaining arguments, then only x will perform as expected; y will return a function waiting for the last argument
const b = R.propEq('a')
const x = b
const y = n => b(n)
// call in curried form, everything works as expected
console.log(x('b')({a: 'b'})) // true
console.log(y('b')({a: 'b'})) // true
// call with both args, y blows up
console.log(x('b', {a: 'b'})) // true
console.log(y('b', {a: 'b'})) // function n(r){return 0===arguments.length||b(r)?n:t.apply(this,arguments)}
The error is of course because of the way we defined y
// bad, only accommodates one extra argument
// ramda super magical api would allow any number of arguments per application
const y = n => b(n)
// instead write
const y = (...args) => b(...args)
// above: which of course is stupid in a whole new way
// instead just write
const y = b
// above which is stupid, too
// instead just write
b
Your intention
I (think) I understand what you're trying to do in your updated post. If so, the following snippet might be of some help to you
const fieldEq = R.propEq('field')
const errorsInclude = type =>
R.compose (R.any(fieldEq(type)), R.prop('errors'))
const addingError = {
message: '',
errors: [ { field: "number" }, { field: "mac" } ]
}
errorsInclude('mac') (addingError) // true
errorsInclude('number') (addingError) // true
errorsInclude('foo') (addingError) // false
Be careful not to fetishize point-free programming. In the code above, errorsInclude must be called in curried form. The Ramda Way® might suggest you use R.curry for the binary function
const errorsInclude = R.curry((type, x) =>
R.compose (R.any(fieldEq(type)), R.prop('errors')) (x))
// now you can call it either way
console.log(errorsInclude('mac', addingError)) // true
console.log(errorsInclude('mac')(addingError)) // true
But! this sorta defeats the purpose of R.compose – I personally think the following is probably the best you can end up with if you want to adhere to ramda conventions
const errorsInclude = R.curry((type, x) =>
R.any(fieldEq(type), R.prop('errors', x)))
There's nothing sexy about it, but it at least it's straightforward – just my 2 cents.
#ScottSauyet comments that it could also be solved using R.useWith:
const errorsInclude = R.useWith(R.any, [R.propEq('field'), R.prop('errors')]);
For what it's worth
Your question title is at the core of lambda calculus' eta conversion –
const g = x => f (x) == f
g(y) == f(y)
g == f
This only works as a law when all functions accept/expect exactly 1 argument tho (which is the case in lambda calculus).
The typical way to loop x times in JavaScript is:
for (var i = 0; i < x; i++)
doStuff(i);
But I don't want to use the ++ operator or have any mutable variables at all. So is there a way, in ES6, to loop x times another way? I love Ruby's mechanism:
x.times do |i|
do_stuff(i)
end
Anything similar in JavaScript/ES6? I could kind of cheat and make my own generator:
function* times(x) {
for (var i = 0; i < x; i++)
yield i;
}
for (var i of times(5)) {
console.log(i);
}
Of course I'm still using i++. At least it's out of sight :), but I'm hoping there's a better mechanism in ES6.
Using the ES2015 Spread operator:
[...Array(n)].map()
const res = [...Array(10)].map((_, i) => {
return i * 10;
});
// as a one liner
const res = [...Array(10)].map((_, i) => i * 10);
Or if you don't need the result:
[...Array(10)].forEach((_, i) => {
console.log(i);
});
// as a one liner
[...Array(10)].forEach((_, i) => console.log(i));
Or using the ES2015 Array.from operator:
Array.from(...)
const res = Array.from(Array(10)).map((_, i) => {
return i * 10;
});
// as a one liner
const res = Array.from(Array(10)).map((_, i) => i * 10);
Note that if you just need a string repeated you can use String.prototype.repeat.
console.log("0".repeat(10))
// 0000000000
OK!
The code below is written using ES6 syntaxes but could just as easily be written in ES5 or even less. ES6 is not a requirement to create a "mechanism to loop x times"
If you don't need the iterator in the callback, this is the most simple implementation
const times = x => f => {
if (x > 0) {
f()
times (x - 1) (f)
}
}
// use it
times (3) (() => console.log('hi'))
// or define intermediate functions for reuse
let twice = times (2)
// twice the power !
twice (() => console.log('double vision'))
If you do need the iterator, you can use a named inner function with a counter parameter to iterate for you
const times = n => f => {
let iter = i => {
if (i === n) return
f (i)
iter (i + 1)
}
return iter (0)
}
times (3) (i => console.log(i, 'hi'))
Stop reading here if you don't like learning more things ...
But something should feel off about those...
single branch if statements are ugly — what happens on the other branch ?
multiple statements/expressions in the function bodies — are procedure concerns being mixed ?
implicitly returned undefined — indication of impure, side-effecting function
"Isn't there a better way ?"
There is. Let's first revisit our initial implementation
// times :: Int -> (void -> void) -> void
const times = x => f => {
if (x > 0) {
f() // has to be side-effecting function
times (x - 1) (f)
}
}
Sure, it's simple, but notice how we just call f() and don't do anything with it. This really limits the type of function we can repeat multiple times. Even if we have the iterator available, f(i) isn't much more versatile.
What if we start with a better kind of function repetition procedure ? Maybe something that makes better use of input and output.
Generic function repetition
// repeat :: forall a. Int -> (a -> a) -> a -> a
const repeat = n => f => x => {
if (n > 0)
return repeat (n - 1) (f) (f (x))
else
return x
}
// power :: Int -> Int -> Int
const power = base => exp => {
// repeat <exp> times, <base> * <x>, starting with 1
return repeat (exp) (x => base * x) (1)
}
console.log(power (2) (8))
// => 256
Above, we defined a generic repeat function which takes an additional input which is used to start the repeated application of a single function.
// repeat 3 times, the function f, starting with x ...
var result = repeat (3) (f) (x)
// is the same as ...
var result = f(f(f(x)))
Implementing times with repeat
Well this is easy now; almost all of the work is already done.
// repeat :: forall a. Int -> (a -> a) -> a -> a
const repeat = n => f => x => {
if (n > 0)
return repeat (n - 1) (f) (f (x))
else
return x
}
// times :: Int -> (Int -> Int) -> Int
const times = n=> f=>
repeat (n) (i => (f(i), i + 1)) (0)
// use it
times (3) (i => console.log(i, 'hi'))
Since our function takes i as an input and returns i + 1, this effectively works as our iterator which we pass to f each time.
We've fixed our bullet list of issues too
No more ugly single branch if statements
Single-expression bodies indicate nicely separated concerns
No more useless, implicitly returned undefined
JavaScript comma operator, the
In case you're having trouble seeing how the last example is working, it depends on your awareness of one of JavaScript's oldest battle axes; the comma operator – in short, it evaluates expressions from left to right and returns the value of the last evaluated expression
(expr1 :: a, expr2 :: b, expr3 :: c) :: c
In our above example, I'm using
(i => (f(i), i + 1))
which is just a succinct way of writing
(i => { f(i); return i + 1 })
Tail Call Optimisation
As sexy as the recursive implementations are, at this point it would be irresponsible for me to recommend them given that no JavaScript VM I can think of supports proper tail call elimination – babel used to transpile it, but it's been in "broken; will reimplement" status for well over a year.
repeat (1e6) (someFunc) (x)
// => RangeError: Maximum call stack size exceeded
As such, we should revisit our implementation of repeat to make it stack-safe.
The code below does use mutable variables n and x but note that all mutations are localized to the repeat function – no state changes (mutations) are visible from outside of the function
// repeat :: Int -> (a -> a) -> (a -> a)
const repeat = n => f => x =>
{
let m = 0, acc = x
while (m < n)
(m = m + 1, acc = f (acc))
return acc
}
// inc :: Int -> Int
const inc = x =>
x + 1
console.log (repeat (1e8) (inc) (0))
// 100000000
This is going to have a lot of you saying "but that's not functional !" – I know, just relax. We can implement a Clojure-style loop/recur interface for constant-space looping using pure expressions; none of that while stuff.
Here we abstract while away with our loop function – it looks for a special recur type to keep the loop running. When a non-recur type is encountered, the loop is finished and the result of the computation is returned
const recur = (...args) =>
({ type: recur, args })
const loop = f =>
{
let acc = f ()
while (acc.type === recur)
acc = f (...acc.args)
return acc
}
const repeat = $n => f => x =>
loop ((n = $n, acc = x) =>
n === 0
? acc
: recur (n - 1, f (acc)))
const inc = x =>
x + 1
const fibonacci = $n =>
loop ((n = $n, a = 0, b = 1) =>
n === 0
? a
: recur (n - 1, b, a + b))
console.log (repeat (1e7) (inc) (0)) // 10000000
console.log (fibonacci (100)) // 354224848179262000000
for (let i of Array(100).keys()) {
console.log(i)
}
Here is another good alternative:
Array.from({ length: 3}).map(...);
Preferably, as #Dave Morse pointed out in the comments, you can also get rid of the map call, by using the second parameter of the Array.from function like so:
Array.from({ length: 3 }, () => (...))
I think the best solution is to use let:
for (let i=0; i<100; i++) …
That will create a new (mutable) i variable for each body evaluation and assures that the i is only changed in the increment expression in that loop syntax, not from anywhere else.
I could kind of cheat and make my own generator. At least i++ is out of sight :)
That should be enough, imo. Even in pure languages, all operations (or at least, their interpreters) are built from primitives that use mutation. As long as it is properly scoped, I cannot see what is wrong with that.
You should be fine with
function* times(n) {
for (let i = 0; i < n; i++)
yield i;
}
for (const i of times(5)) {
console.log(i);
}
But I don't want to use the ++ operator or have any mutable variables at all.
Then your only choice is to use recursion. You can define that generator function without a mutable i as well:
function* range(i, n) {
if (i >= n) return;
yield i;
return yield* range(i+1, n);
}
times = (n) => range(0, n);
But that seems overkill to me and might have performance problems (as tail call elimination is not available for return yield*).
I think it is pretty simple:
[...Array(3).keys()]
or
Array(3).fill()
const times = 4;
new Array(times).fill().map(() => console.log('test'));
This snippet will console.log test 4 times.
Answer: 09 December 2015
Personally, I found the accepted answer both concise (good) and terse (bad). Appreciate this statement might be subjective, so please read this answer and see if you agree or disagree
The example given in the question was something like Ruby's:
x.times do |i|
do_stuff(i)
end
Expressing this in JS using below would permit:
times(x)(doStuff(i));
Here is the code:
let times = (n) => {
return (f) => {
Array(n).fill().map((_, i) => f(i));
};
};
That's it!
Simple example usage:
let cheer = () => console.log('Hip hip hooray!');
times(3)(cheer);
//Hip hip hooray!
//Hip hip hooray!
//Hip hip hooray!
Alternatively, following the examples of the accepted answer:
let doStuff = (i) => console.log(i, ' hi'),
once = times(1),
twice = times(2),
thrice = times(3);
once(doStuff);
//0 ' hi'
twice(doStuff);
//0 ' hi'
//1 ' hi'
thrice(doStuff);
//0 ' hi'
//1 ' hi'
//2 ' hi'
Side note - Defining a range function
A similar / related question, that uses fundamentally very similar code constructs, might be is there a convenient Range function in (core) JavaScript, something similar to underscore's range function.
Create an array with n numbers, starting from x
Underscore
_.range(x, x + n)
ES2015
Couple of alternatives:
Array(n).fill().map((_, i) => x + i)
Array.from(Array(n), (_, i) => x + i)
Demo using n = 10, x = 1:
> Array(10).fill().map((_, i) => i + 1)
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
> Array.from(Array(10), (_, i) => i + 1)
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
In a quick test I ran, with each of the above running a million times each using our solution and doStuff function, the former approach (Array(n).fill()) proved slightly faster.
I am late to the party, but since this question turns up often in search results, I would just like to add a solution that I consider to be the best in terms of readability while not being long (which is ideal for any codebase IMO). It mutates, but I'd make that tradeoff for KISS principles.
let times = 5
while( times-- )
console.log(times)
// logs 4, 3, 2, 1, 0
Array(100).fill().map((_,i)=> console.log(i) );
This version satisifies the OP's requirement for immutability. Also consider using reduce instead of map depending on your use case.
This is also an option if you don't mind a little mutation in your prototype.
Number.prototype.times = function(f) {
return Array(this.valueOf()).fill().map((_,i)=>f(i));
};
Now we can do this
((3).times(i=>console.log(i)));
+1 to arcseldon for the .fill suggestion.
Not something I would teach (or ever use in my code), but here's a codegolf-worthy solution without mutating a variable, no need for ES6:
Array.apply(null, {length: 10}).forEach(function(_, i){
doStuff(i);
})
More of an interesting proof-of-concept thing than a useful answer, really.
If you're willing to use a library, there's also lodash _.times or underscore _.times:
_.times(x, i => {
return doStuff(i)
})
Note this returns an array of the results, so it's really more like this ruby:
x.times.map { |i|
doStuff(i)
}
Afaik, there is no mechanism in ES6 similar to Ruby's times method. But you can avoid mutation by using recursion:
let times = (i, cb, l = i) => {
if (i === 0) return;
cb(l - i);
times(i - 1, cb, l);
}
times(5, i => doStuff(i));
Demo: http://jsbin.com/koyecovano/1/edit?js,console
In the functional paradigm repeat is usually an infinite recursive function. To use it we need either lazy evaluation or continuation passing style.
Lazy evaluated function repetition
const repeat = f => x => [x, () => repeat(f) (f(x))];
const take = n => ([x, f]) => n === 0 ? x : take(n - 1) (f());
console.log(
take(8) (repeat(x => x * 2) (1)) // 256
);
I use a thunk (a function without arguments) to achieve lazy evaluation in Javascript.
Function repetition with continuation passing style
const repeat = f => x => [x, k => k(repeat(f) (f(x)))];
const take = n => ([x, k]) => n === 0 ? x : k(take(n - 1));
console.log(
take(8) (repeat(x => x * 2) (1)) // 256
);
CPS is a little scary at first. However, it always follows the same pattern: The last argument is the continuation (a function), which invokes its own body: k => k(...). Please note that CPS turns the application inside out, i.e. take(8) (repeat...) becomes k(take(8)) (...) where k is the partially applied repeat.
Conclusion
By separating the repetition (repeat) from the termination condition (take) we gain flexibility - separation of concerns up to its bitter end :D
Advantages of this solution
Simplest to read / use (imo)
Return value can be used as a sum, or just ignored
Plain es6 version, also link to TypeScript version of the code
Disadvantages
- Mutation. Being internal only I don't care, maybe some others will not either.
Examples and Code
times(5, 3) // 15 (3+3+3+3+3)
times(5, (i) => Math.pow(2,i) ) // 31 (1+2+4+8+16)
times(5, '<br/>') // <br/><br/><br/><br/><br/>
times(3, (i, count) => { // name[0], name[1], name[2]
let n = 'name[' + i + ']'
if (i < count-1)
n += ', '
return n
})
function times(count, callbackOrScalar) {
let type = typeof callbackOrScalar
let sum
if (type === 'number') sum = 0
else if (type === 'string') sum = ''
for (let j = 0; j < count; j++) {
if (type === 'function') {
const callback = callbackOrScalar
const result = callback(j, count)
if (typeof result === 'number' || typeof result === 'string')
sum = sum === undefined ? result : sum + result
}
else if (type === 'number' || type === 'string') {
const scalar = callbackOrScalar
sum = sum === undefined ? scalar : sum + scalar
}
}
return sum
}
TypeScipt version
https://codepen.io/whitneyland/pen/aVjaaE?editors=0011
The simplest way I can think of for creating list/array within range
Array.from(Array(max-min+1), (_, index) => index+min)
I have another alternative
[...Array(30).keys()]
addressing the functional aspect:
function times(n, f) {
var _f = function (f) {
var i;
for (i = 0; i < n; i++) {
f(i);
}
};
return typeof f === 'function' && _f(f) || _f;
}
times(6)(function (v) {
console.log('in parts: ' + v);
});
times(6, function (v) {
console.log('complete: ' + v);
});
Generators? Recursion? Why so much hatin' on mutatin'? ;-)
If it is acceptable as long as we "hide" it, then just accept the use of a unary operator and we can keep things simple:
Number.prototype.times = function(f) { let n=0 ; while(this.valueOf() > n) f(n++) }
Just like in ruby:
> (3).times(console.log)
0
1
2
I wrapped #Tieme s answer with a helper function.
In TypeScript:
export const mapN = <T = any[]>(count: number, fn: (...args: any[]) => T): T[] => [...Array(count)].map((_, i) => fn())
Now you can run:
const arr: string[] = mapN(3, () => 'something')
// returns ['something', 'something', 'something']
I made this:
function repeat(func, times) {
for (var i=0; i<times; i++) {
func(i);
}
}
Usage:
repeat(function(i) {
console.log("Hello, World! - "+i);
}, 5)
/*
Returns:
Hello, World! - 0
Hello, World! - 1
Hello, World! - 2
Hello, World! - 3
Hello, World! - 4
*/
The i variable returns the amount of times it has looped - useful if you need to preload an x amount of images.
I am just going to put this here. If you are looking for a compact function without using Arrays and you have no issue with mutability/immutability :
var g =x=>{/*your code goes here*/x-1>0?g(x-1):null};
For me, this is the easiest answer to understand for many levels of developers
const times = (n, callback) => {
while (n) {
callback();
n--;
}
}
times(10, ()=> console.log('hello'))
It seems to me that the most correct answer (which is debatable) to this question is buried in a comment by Sasha Kondrashov and is also the most concise, using just two characters: "no". There is no functional alternative to a for-loop as nice as the syntax that Ruby has. We might want there to be one, but there just isn't.
It is not explicitly stated in the question, but I would argue any solution to the problem of 'looping N times' should not allocate memory, at least not proportional to N. That criterium would rule out most of the answers that are 'native to javascript'.
Other answers show implementations like the one in Ruby, which is fine, except that the question explicitly asks for a native javascript solution. And there is already a very decent hand-rolled solution in the question, arguably one of the most readable of all.
I'm learning functional programming and I wonder if there is a way to "combine" functions like this:
function triple(x) {
return x * 3;
}
function plusOne(x) {
return x + 1;
}
function isZero(x) {
return x === 0;
}
combine(1); //1
combine(triple)(triple)(plusOne)(1); // 10
combine(plusOne)(triple)(isZero)(-1); // true
If the para is a function, it "combines" the function into itself, and if not it will return the final result.
Thanks!
heritage
This is a concept from maths called function composition.
f(x) = y
g(y) = z
g(f(x)) = z
(g•f)(x) = z
That last line is read "g of f of x equals z". What's great about composed functions is the elimination of points. Notice in g(f(x)) = z we take an x input and get a z output. This skips the intermediate point, y.
Composition is a great way to create higher-order functions and keep your code sparkly clean. It's plain to see why we'd want this in our Javascript programs.
comp
JavaScript is a multi-paradigm language with rich support for functions. We can create a simple comp function, which combines two input functions, g and f, and results in a new function -
function triple(x) {
return x * 3
}
function plusOne(x) {
return x + 1
}
function comp(g, f) {
return function(x) {
return g(f(x)) // "g of f of x"
}
}
const myfunc =
comp(triple, plusOne)
console.log(myfunc(1))
Evaluation
triple(plusOne(1))
triple(2)
6
compose
Just as the question suggests, it's likely we will want to combine more than two functions. Below we write compose which takes all of the input functions and reduces them using our simple comp from above. If no functions are given, we return the empty function, identity -
const triple = (x) =>
x * 3
const plusOne = (x) =>
x + 1
const comp = (g, f) =>
x => g(f(x)) // "g of f of x"
const identity = (x) =>
x
const compose = (...all) =>
all.reduce(comp, identity)
const myfunc =
compose(triple, triple, plusOne) // any amount of funcs
console.log(myfunc(1))
Evaluation
triple(triple(plusOne(1)))
triple(triple(2))
triple(6)
18
pipe
You can be as creative as you like. Below, we write pipe which allows our programs to read in a comfortable left-to-right direction -
const triple = (x) =>
x * 3
const plusOne = (x) =>
x + 1
const pipe = x =>
f => pipe(f(x))
pipe(1)(plusOne)(triple)(triple)(console.log) // 18
pipe(3)(triple)(plusOne)(triple)(plusOne)(console.log) // 31
Evaluation of expression one -
f => pipe(f(1))
pipe(plusOne(1))
f => pipe(f(2))
pipe(triple(2))
f => pipe(f(6))
pipe(triple(6))
f => pipe(f(18))
pipe(console.log(18))
18
and expression two -
f => pipe(f(3))
pipe(triple(3))
f => pipe(f(9))
pipe(plusOne(9))
f => pipe(f(10))
pipe(triple(10))
f => pipe(f(30))
pipe(plusOne(31))
f => pipe(f(31))
pipe(console.log(31))
31
related techniques
Curried functions and partial application are concepts that gel with function composition. pipe above is introduced in another Q&A as $ and demonstrated again here -
const $ = x => // "pipe", or whatever name you pick
k => $ (k (x))
const add = x => y => // curried add
x + y
const mult = x => y => // curried mult
x * y
$ (1) // 1
(add (2)) // + 2 = 3
(mult (6)) // * 6 = 18
(console.log) // 18
$ (7) // 7
(add (1)) // + 1 = 8
(mult (8)) // * 8 = 64
(mult (2)) // * 2 = 128
(mult (2)) // * 2 = 256
(console.log) // 256
function triple(x) {
return x * 3;
}
function plusOne(x) {
return x + 1;
}
function isZero(x) {
return x === 0;
}
var combine = function (v) {
var fn = [];
function _f(v) {
if (typeof v === 'function') {
fn.push(v);
return _f;
} else {
return fn.reduce(function (x, f) { return f(x); }, v);
}
}
return _f(v);
};
var a, b;
console.log(combine(1)); //1
console.log(combine(triple)(triple)(plusOne)(1)); // 10
console.log(combine(plusOne)(triple)(isZero)(-1)); // true
console.log(a = combine(plusOne)); // function ...
console.log(b = a(triple)); // function ...
console.log(b(5)); // 18
console.log(combine(triple)(plusOne)(triple)(plusOne)(triple)(plusOne)(1)); // 40
// #naomik's examples
var f = combine(triple);
var g = combine(triple)(triple);
console.log(f(1)); // 3
console.log(g(1)); // 9 (not 6 as you stated)
Function composition has already been detailed in other answers, mostly https://stackoverflow.com/a/30198265/4099454, so my 2 cents are straight onto answering your latest question:
If the para is a function, it "combines" the function into itself, and if not it will return the final result. Thanks!
const chain = (g, f = x => x) =>
typeof g === 'function'
? (y) => chain(y, (x) => g(f(x)))
: f(g);
// ====
const triple = x => x * 3;
const inc = x => x + 1;
const isZero = x => x === 0;
console.log(
chain(inc)(triple)(isZero)(-1),
);
It is also possible to build a complex Functionality by Composing Simple Functions in JavaScript.In a sense, the composition is the nesting of functions, passing the result of one in as the input into the next. But rather than creating an indecipherable amount of nesting, we'll create a higher-order function, compose(), that takes all of the functions we want to combine, and returns us a new function to use in our app.
function triple(x) {
return x * 3;
}
function plusOne(x) {
return x + 1;
}
function isZero(x) {
return x === 0;
}
const compose = (...fns) => x =>
fns.reduce((acc, cur) => {
return cur(acc);
}, x);
const withCompose = compose(triple, triple, isZero);
console.log(withCompose(1));
You can simply call the function on the return values themselves, for example:
plusOne(triple(triple(1))) // 10
isZero(triple(plusOne(-1))) // true