Calling and Passing Nested Functions in JavaScript
I have a function that returns the LCM of a range of numbers. It works great, but this has a function inside of a function inside of a function. My question is why can I not simplify the nested smallestCommon() by removing scm() from inside of it? Why does this particular solution need this if else functionality so deeply nested?
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
var candidate = max;
var smallestCommon = function(low, high) {
// inner function to use 'high' variable
function scm(l, h) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high);
}
}
return scm(low, high);
};
for (var i = min; i <= max; i += 1) {
candidate = smallestCommon(i, candidate);
}
return candidate;
}
smallestCommons([5, 1]); // should return 60
smallestCommons([1, 13]); // should return 360360
smallestCommons([23, 18]); //should return 6056820
javascript function callback nested-function
add a comment |
I have a function that returns the LCM of a range of numbers. It works great, but this has a function inside of a function inside of a function. My question is why can I not simplify the nested smallestCommon() by removing scm() from inside of it? Why does this particular solution need this if else functionality so deeply nested?
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
var candidate = max;
var smallestCommon = function(low, high) {
// inner function to use 'high' variable
function scm(l, h) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high);
}
}
return scm(low, high);
};
for (var i = min; i <= max; i += 1) {
candidate = smallestCommon(i, candidate);
}
return candidate;
}
smallestCommons([5, 1]); // should return 60
smallestCommons([1, 13]); // should return 360360
smallestCommons([23, 18]); //should return 6056820
javascript function callback nested-function
Does LCM = lowest common multiple? If so, it's not clear why the LCM of[5, 1]
is60
.
– Mark Meyer
Nov 15 '18 at 17:09
(LCM = Least Common Multiple) The LCM of 5 and 1 is 5. The LCM of 1 and 13 is 13. The LCM of 23 and 18 is 414. I'm a little confused as what you're after. There is no need to nest the declarations of these functions. They will run faster if you extract thescm
function and just call it inside ofsmallestCommons
. ThesmallestCommon
function is completely extraneous considering all it does is definescm
and return an invocation ofscm
.
– Kyle Richardson
Nov 15 '18 at 17:13
add a comment |
I have a function that returns the LCM of a range of numbers. It works great, but this has a function inside of a function inside of a function. My question is why can I not simplify the nested smallestCommon() by removing scm() from inside of it? Why does this particular solution need this if else functionality so deeply nested?
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
var candidate = max;
var smallestCommon = function(low, high) {
// inner function to use 'high' variable
function scm(l, h) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high);
}
}
return scm(low, high);
};
for (var i = min; i <= max; i += 1) {
candidate = smallestCommon(i, candidate);
}
return candidate;
}
smallestCommons([5, 1]); // should return 60
smallestCommons([1, 13]); // should return 360360
smallestCommons([23, 18]); //should return 6056820
javascript function callback nested-function
I have a function that returns the LCM of a range of numbers. It works great, but this has a function inside of a function inside of a function. My question is why can I not simplify the nested smallestCommon() by removing scm() from inside of it? Why does this particular solution need this if else functionality so deeply nested?
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
var candidate = max;
var smallestCommon = function(low, high) {
// inner function to use 'high' variable
function scm(l, h) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high);
}
}
return scm(low, high);
};
for (var i = min; i <= max; i += 1) {
candidate = smallestCommon(i, candidate);
}
return candidate;
}
smallestCommons([5, 1]); // should return 60
smallestCommons([1, 13]); // should return 360360
smallestCommons([23, 18]); //should return 6056820
javascript function callback nested-function
javascript function callback nested-function
asked Nov 15 '18 at 17:05
Adam SchorkAdam Schork
11
11
Does LCM = lowest common multiple? If so, it's not clear why the LCM of[5, 1]
is60
.
– Mark Meyer
Nov 15 '18 at 17:09
(LCM = Least Common Multiple) The LCM of 5 and 1 is 5. The LCM of 1 and 13 is 13. The LCM of 23 and 18 is 414. I'm a little confused as what you're after. There is no need to nest the declarations of these functions. They will run faster if you extract thescm
function and just call it inside ofsmallestCommons
. ThesmallestCommon
function is completely extraneous considering all it does is definescm
and return an invocation ofscm
.
– Kyle Richardson
Nov 15 '18 at 17:13
add a comment |
Does LCM = lowest common multiple? If so, it's not clear why the LCM of[5, 1]
is60
.
– Mark Meyer
Nov 15 '18 at 17:09
(LCM = Least Common Multiple) The LCM of 5 and 1 is 5. The LCM of 1 and 13 is 13. The LCM of 23 and 18 is 414. I'm a little confused as what you're after. There is no need to nest the declarations of these functions. They will run faster if you extract thescm
function and just call it inside ofsmallestCommons
. ThesmallestCommon
function is completely extraneous considering all it does is definescm
and return an invocation ofscm
.
– Kyle Richardson
Nov 15 '18 at 17:13
Does LCM = lowest common multiple? If so, it's not clear why the LCM of
[5, 1]
is 60
.– Mark Meyer
Nov 15 '18 at 17:09
Does LCM = lowest common multiple? If so, it's not clear why the LCM of
[5, 1]
is 60
.– Mark Meyer
Nov 15 '18 at 17:09
(LCM = Least Common Multiple) The LCM of 5 and 1 is 5. The LCM of 1 and 13 is 13. The LCM of 23 and 18 is 414. I'm a little confused as what you're after. There is no need to nest the declarations of these functions. They will run faster if you extract the
scm
function and just call it inside of smallestCommons
. The smallestCommon
function is completely extraneous considering all it does is define scm
and return an invocation of scm
.– Kyle Richardson
Nov 15 '18 at 17:13
(LCM = Least Common Multiple) The LCM of 5 and 1 is 5. The LCM of 1 and 13 is 13. The LCM of 23 and 18 is 414. I'm a little confused as what you're after. There is no need to nest the declarations of these functions. They will run faster if you extract the
scm
function and just call it inside of smallestCommons
. The smallestCommon
function is completely extraneous considering all it does is define scm
and return an invocation of scm
.– Kyle Richardson
Nov 15 '18 at 17:13
add a comment |
3 Answers
3
active
oldest
votes
Having inner functions isn't necessarily bad. Sometimes you want to reduce some local duplication, but don't want to also create a new top-level function. Used carefully, they can clean up code.
In your particular case though, it isn't necessary to have it nested. You can just pass in the high
variable as a third parameter:
function scm(l, h, high) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high, high);
}
}
function smallestCommon (low, high) {
return scm(low, high, high);
}
This is actually a fairly common pattern when dealing with recursion: have a recursive function, and a helper function that simplifies calling the recursive function. In functional languages where recursion is common though, it's actually commonplace to have a local recursive function like you had originally (often called something like go
).
And it's a shame that JS doesn't have a range
function. smallestCommons
is basically just a reduction over the range [min,max]
. Between the lack of range
function and smallestCommon
having it's arguments in the wrong order though, converting your code to use reduce
unfortunately got a little bulky:
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return Array.from(new Array(max - min), (x,i) => i + min)
.reduce((acc, i) => smallestCommon(i, acc), max);
}
Great explanation and I completely agree with your assessment of this use case.
– Kyle Richardson
Nov 15 '18 at 17:17
Nice answer. We approach the problem similarly :D
– user633183
Nov 15 '18 at 18:21
add a comment |
You can unnest it, if you rewrite the inner functions in such a way, that they don't reference variables in their outer scope.
function scm(l, h, step) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + h, step);
}
}
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return scm(min, max, max);
}
It might blow your stack though, but that's a different problem. If you get a RangeError
, you have to rewrite scm
to be loop based instead of recursive.
add a comment |
I'll suggest breaking this down into smaller parts. Instead of one function that's complicated and difficult to debug, you'll have lots of functions that are easy to write and debug. Smaller functions are easier to test and reuse in other parts of your program too -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
console.log
( lcm (1, 5) // 5
, lcm (3, 4) // 12
, lcm (23, 18) // 414
)
Now we have minmax
. Unique to this implementation is that it finds the min and the max using only a single traversal of the input array -
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...rest ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( rest
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
console.log
( minmax ([ 3, 4, 2, 5, 1 ]) // [ 1, 5 ]
, minmax ([ 1, 5 ]) // [ 1, 5 ]
, minmax ([ 5, 1 ]) // [ 1, 5 ]
, minmax ([ 9 ]) // [ 9, 9 ]
, minmax () // [ Infinity, -Infinity ]
)
By default minmax
returns a list
of the min and max values. We can plug the min and max directly into a range
function, which might be more useful to us, as we'll see later -
const range = (m, n) =>
m > n
?
: [ m, ... range (m + 1, n ) ]
console.log
( minmax ([ 3, 4, 2, 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 1, 5 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 9 ], range) // [ 9 ]
, minmax (, range) //
)
Now that we can find the min and max of the input, create a range between the two, all that's left is calculating the lcm
of the values in the range. Taking many values and reducing them to a single value is done with .reduce -
console.log
( minmax ([1, 5], range) .reduce (lcm, 1) // 60
, minmax ([5, 1], range) .reduce (lcm, 1) // 60
)
Wrap that up in a function and we're done -
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
Verify the result in your own browser below -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...xs ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( xs
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
const range = (m, n) =>
m > n
?
: [ m, ... range (m + 1, n ) ]
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
extra
Above, minmax
is defined using continuation passing style. We save extra computation by passing range
as the specified continuation (then
). However, we can call minmax
without specifying a continuation and spread (...
) the intermediate value to range
. Either program might make more sense to you. The result is the same -
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
same pig, different farm
smallestCommons
is basically just a reduction over the range[min,max]
- @Carcigenicate
Hopefully it helps to see the same result from multiple approaches :D
sourface
Some people will despise the above implementation of minmax
regardless of its elegance and flexibility. Now that we maybe understand reducing a little better, we can show how minmax
might be better implemented using direct style -
const minmax = xs =>
xs .reduce
( ([ min, max ], x) =>
[ Math.min (min, x)
, Math.max (max, x)
]
, [ Infinity, -Infinity ]
)
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1) // direct style now required here
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53324572%2fcalling-and-passing-nested-functions-in-javascript%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Having inner functions isn't necessarily bad. Sometimes you want to reduce some local duplication, but don't want to also create a new top-level function. Used carefully, they can clean up code.
In your particular case though, it isn't necessary to have it nested. You can just pass in the high
variable as a third parameter:
function scm(l, h, high) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high, high);
}
}
function smallestCommon (low, high) {
return scm(low, high, high);
}
This is actually a fairly common pattern when dealing with recursion: have a recursive function, and a helper function that simplifies calling the recursive function. In functional languages where recursion is common though, it's actually commonplace to have a local recursive function like you had originally (often called something like go
).
And it's a shame that JS doesn't have a range
function. smallestCommons
is basically just a reduction over the range [min,max]
. Between the lack of range
function and smallestCommon
having it's arguments in the wrong order though, converting your code to use reduce
unfortunately got a little bulky:
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return Array.from(new Array(max - min), (x,i) => i + min)
.reduce((acc, i) => smallestCommon(i, acc), max);
}
Great explanation and I completely agree with your assessment of this use case.
– Kyle Richardson
Nov 15 '18 at 17:17
Nice answer. We approach the problem similarly :D
– user633183
Nov 15 '18 at 18:21
add a comment |
Having inner functions isn't necessarily bad. Sometimes you want to reduce some local duplication, but don't want to also create a new top-level function. Used carefully, they can clean up code.
In your particular case though, it isn't necessary to have it nested. You can just pass in the high
variable as a third parameter:
function scm(l, h, high) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high, high);
}
}
function smallestCommon (low, high) {
return scm(low, high, high);
}
This is actually a fairly common pattern when dealing with recursion: have a recursive function, and a helper function that simplifies calling the recursive function. In functional languages where recursion is common though, it's actually commonplace to have a local recursive function like you had originally (often called something like go
).
And it's a shame that JS doesn't have a range
function. smallestCommons
is basically just a reduction over the range [min,max]
. Between the lack of range
function and smallestCommon
having it's arguments in the wrong order though, converting your code to use reduce
unfortunately got a little bulky:
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return Array.from(new Array(max - min), (x,i) => i + min)
.reduce((acc, i) => smallestCommon(i, acc), max);
}
Great explanation and I completely agree with your assessment of this use case.
– Kyle Richardson
Nov 15 '18 at 17:17
Nice answer. We approach the problem similarly :D
– user633183
Nov 15 '18 at 18:21
add a comment |
Having inner functions isn't necessarily bad. Sometimes you want to reduce some local duplication, but don't want to also create a new top-level function. Used carefully, they can clean up code.
In your particular case though, it isn't necessary to have it nested. You can just pass in the high
variable as a third parameter:
function scm(l, h, high) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high, high);
}
}
function smallestCommon (low, high) {
return scm(low, high, high);
}
This is actually a fairly common pattern when dealing with recursion: have a recursive function, and a helper function that simplifies calling the recursive function. In functional languages where recursion is common though, it's actually commonplace to have a local recursive function like you had originally (often called something like go
).
And it's a shame that JS doesn't have a range
function. smallestCommons
is basically just a reduction over the range [min,max]
. Between the lack of range
function and smallestCommon
having it's arguments in the wrong order though, converting your code to use reduce
unfortunately got a little bulky:
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return Array.from(new Array(max - min), (x,i) => i + min)
.reduce((acc, i) => smallestCommon(i, acc), max);
}
Having inner functions isn't necessarily bad. Sometimes you want to reduce some local duplication, but don't want to also create a new top-level function. Used carefully, they can clean up code.
In your particular case though, it isn't necessary to have it nested. You can just pass in the high
variable as a third parameter:
function scm(l, h, high) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high, high);
}
}
function smallestCommon (low, high) {
return scm(low, high, high);
}
This is actually a fairly common pattern when dealing with recursion: have a recursive function, and a helper function that simplifies calling the recursive function. In functional languages where recursion is common though, it's actually commonplace to have a local recursive function like you had originally (often called something like go
).
And it's a shame that JS doesn't have a range
function. smallestCommons
is basically just a reduction over the range [min,max]
. Between the lack of range
function and smallestCommon
having it's arguments in the wrong order though, converting your code to use reduce
unfortunately got a little bulky:
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return Array.from(new Array(max - min), (x,i) => i + min)
.reduce((acc, i) => smallestCommon(i, acc), max);
}
edited Nov 15 '18 at 17:38
answered Nov 15 '18 at 17:15
CarcigenicateCarcigenicate
18.1k43162
18.1k43162
Great explanation and I completely agree with your assessment of this use case.
– Kyle Richardson
Nov 15 '18 at 17:17
Nice answer. We approach the problem similarly :D
– user633183
Nov 15 '18 at 18:21
add a comment |
Great explanation and I completely agree with your assessment of this use case.
– Kyle Richardson
Nov 15 '18 at 17:17
Nice answer. We approach the problem similarly :D
– user633183
Nov 15 '18 at 18:21
Great explanation and I completely agree with your assessment of this use case.
– Kyle Richardson
Nov 15 '18 at 17:17
Great explanation and I completely agree with your assessment of this use case.
– Kyle Richardson
Nov 15 '18 at 17:17
Nice answer. We approach the problem similarly :D
– user633183
Nov 15 '18 at 18:21
Nice answer. We approach the problem similarly :D
– user633183
Nov 15 '18 at 18:21
add a comment |
You can unnest it, if you rewrite the inner functions in such a way, that they don't reference variables in their outer scope.
function scm(l, h, step) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + h, step);
}
}
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return scm(min, max, max);
}
It might blow your stack though, but that's a different problem. If you get a RangeError
, you have to rewrite scm
to be loop based instead of recursive.
add a comment |
You can unnest it, if you rewrite the inner functions in such a way, that they don't reference variables in their outer scope.
function scm(l, h, step) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + h, step);
}
}
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return scm(min, max, max);
}
It might blow your stack though, but that's a different problem. If you get a RangeError
, you have to rewrite scm
to be loop based instead of recursive.
add a comment |
You can unnest it, if you rewrite the inner functions in such a way, that they don't reference variables in their outer scope.
function scm(l, h, step) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + h, step);
}
}
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return scm(min, max, max);
}
It might blow your stack though, but that's a different problem. If you get a RangeError
, you have to rewrite scm
to be loop based instead of recursive.
You can unnest it, if you rewrite the inner functions in such a way, that they don't reference variables in their outer scope.
function scm(l, h, step) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + h, step);
}
}
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return scm(min, max, max);
}
It might blow your stack though, but that's a different problem. If you get a RangeError
, you have to rewrite scm
to be loop based instead of recursive.
edited Nov 15 '18 at 17:20
answered Nov 15 '18 at 17:13
DavidDavid
1,133117
1,133117
add a comment |
add a comment |
I'll suggest breaking this down into smaller parts. Instead of one function that's complicated and difficult to debug, you'll have lots of functions that are easy to write and debug. Smaller functions are easier to test and reuse in other parts of your program too -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
console.log
( lcm (1, 5) // 5
, lcm (3, 4) // 12
, lcm (23, 18) // 414
)
Now we have minmax
. Unique to this implementation is that it finds the min and the max using only a single traversal of the input array -
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...rest ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( rest
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
console.log
( minmax ([ 3, 4, 2, 5, 1 ]) // [ 1, 5 ]
, minmax ([ 1, 5 ]) // [ 1, 5 ]
, minmax ([ 5, 1 ]) // [ 1, 5 ]
, minmax ([ 9 ]) // [ 9, 9 ]
, minmax () // [ Infinity, -Infinity ]
)
By default minmax
returns a list
of the min and max values. We can plug the min and max directly into a range
function, which might be more useful to us, as we'll see later -
const range = (m, n) =>
m > n
?
: [ m, ... range (m + 1, n ) ]
console.log
( minmax ([ 3, 4, 2, 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 1, 5 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 9 ], range) // [ 9 ]
, minmax (, range) //
)
Now that we can find the min and max of the input, create a range between the two, all that's left is calculating the lcm
of the values in the range. Taking many values and reducing them to a single value is done with .reduce -
console.log
( minmax ([1, 5], range) .reduce (lcm, 1) // 60
, minmax ([5, 1], range) .reduce (lcm, 1) // 60
)
Wrap that up in a function and we're done -
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
Verify the result in your own browser below -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...xs ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( xs
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
const range = (m, n) =>
m > n
?
: [ m, ... range (m + 1, n ) ]
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
extra
Above, minmax
is defined using continuation passing style. We save extra computation by passing range
as the specified continuation (then
). However, we can call minmax
without specifying a continuation and spread (...
) the intermediate value to range
. Either program might make more sense to you. The result is the same -
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
same pig, different farm
smallestCommons
is basically just a reduction over the range[min,max]
- @Carcigenicate
Hopefully it helps to see the same result from multiple approaches :D
sourface
Some people will despise the above implementation of minmax
regardless of its elegance and flexibility. Now that we maybe understand reducing a little better, we can show how minmax
might be better implemented using direct style -
const minmax = xs =>
xs .reduce
( ([ min, max ], x) =>
[ Math.min (min, x)
, Math.max (max, x)
]
, [ Infinity, -Infinity ]
)
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1) // direct style now required here
add a comment |
I'll suggest breaking this down into smaller parts. Instead of one function that's complicated and difficult to debug, you'll have lots of functions that are easy to write and debug. Smaller functions are easier to test and reuse in other parts of your program too -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
console.log
( lcm (1, 5) // 5
, lcm (3, 4) // 12
, lcm (23, 18) // 414
)
Now we have minmax
. Unique to this implementation is that it finds the min and the max using only a single traversal of the input array -
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...rest ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( rest
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
console.log
( minmax ([ 3, 4, 2, 5, 1 ]) // [ 1, 5 ]
, minmax ([ 1, 5 ]) // [ 1, 5 ]
, minmax ([ 5, 1 ]) // [ 1, 5 ]
, minmax ([ 9 ]) // [ 9, 9 ]
, minmax () // [ Infinity, -Infinity ]
)
By default minmax
returns a list
of the min and max values. We can plug the min and max directly into a range
function, which might be more useful to us, as we'll see later -
const range = (m, n) =>
m > n
?
: [ m, ... range (m + 1, n ) ]
console.log
( minmax ([ 3, 4, 2, 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 1, 5 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 9 ], range) // [ 9 ]
, minmax (, range) //
)
Now that we can find the min and max of the input, create a range between the two, all that's left is calculating the lcm
of the values in the range. Taking many values and reducing them to a single value is done with .reduce -
console.log
( minmax ([1, 5], range) .reduce (lcm, 1) // 60
, minmax ([5, 1], range) .reduce (lcm, 1) // 60
)
Wrap that up in a function and we're done -
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
Verify the result in your own browser below -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...xs ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( xs
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
const range = (m, n) =>
m > n
?
: [ m, ... range (m + 1, n ) ]
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
extra
Above, minmax
is defined using continuation passing style. We save extra computation by passing range
as the specified continuation (then
). However, we can call minmax
without specifying a continuation and spread (...
) the intermediate value to range
. Either program might make more sense to you. The result is the same -
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
same pig, different farm
smallestCommons
is basically just a reduction over the range[min,max]
- @Carcigenicate
Hopefully it helps to see the same result from multiple approaches :D
sourface
Some people will despise the above implementation of minmax
regardless of its elegance and flexibility. Now that we maybe understand reducing a little better, we can show how minmax
might be better implemented using direct style -
const minmax = xs =>
xs .reduce
( ([ min, max ], x) =>
[ Math.min (min, x)
, Math.max (max, x)
]
, [ Infinity, -Infinity ]
)
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1) // direct style now required here
add a comment |
I'll suggest breaking this down into smaller parts. Instead of one function that's complicated and difficult to debug, you'll have lots of functions that are easy to write and debug. Smaller functions are easier to test and reuse in other parts of your program too -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
console.log
( lcm (1, 5) // 5
, lcm (3, 4) // 12
, lcm (23, 18) // 414
)
Now we have minmax
. Unique to this implementation is that it finds the min and the max using only a single traversal of the input array -
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...rest ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( rest
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
console.log
( minmax ([ 3, 4, 2, 5, 1 ]) // [ 1, 5 ]
, minmax ([ 1, 5 ]) // [ 1, 5 ]
, minmax ([ 5, 1 ]) // [ 1, 5 ]
, minmax ([ 9 ]) // [ 9, 9 ]
, minmax () // [ Infinity, -Infinity ]
)
By default minmax
returns a list
of the min and max values. We can plug the min and max directly into a range
function, which might be more useful to us, as we'll see later -
const range = (m, n) =>
m > n
?
: [ m, ... range (m + 1, n ) ]
console.log
( minmax ([ 3, 4, 2, 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 1, 5 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 9 ], range) // [ 9 ]
, minmax (, range) //
)
Now that we can find the min and max of the input, create a range between the two, all that's left is calculating the lcm
of the values in the range. Taking many values and reducing them to a single value is done with .reduce -
console.log
( minmax ([1, 5], range) .reduce (lcm, 1) // 60
, minmax ([5, 1], range) .reduce (lcm, 1) // 60
)
Wrap that up in a function and we're done -
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
Verify the result in your own browser below -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...xs ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( xs
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
const range = (m, n) =>
m > n
?
: [ m, ... range (m + 1, n ) ]
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
extra
Above, minmax
is defined using continuation passing style. We save extra computation by passing range
as the specified continuation (then
). However, we can call minmax
without specifying a continuation and spread (...
) the intermediate value to range
. Either program might make more sense to you. The result is the same -
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
same pig, different farm
smallestCommons
is basically just a reduction over the range[min,max]
- @Carcigenicate
Hopefully it helps to see the same result from multiple approaches :D
sourface
Some people will despise the above implementation of minmax
regardless of its elegance and flexibility. Now that we maybe understand reducing a little better, we can show how minmax
might be better implemented using direct style -
const minmax = xs =>
xs .reduce
( ([ min, max ], x) =>
[ Math.min (min, x)
, Math.max (max, x)
]
, [ Infinity, -Infinity ]
)
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1) // direct style now required here
I'll suggest breaking this down into smaller parts. Instead of one function that's complicated and difficult to debug, you'll have lots of functions that are easy to write and debug. Smaller functions are easier to test and reuse in other parts of your program too -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
console.log
( lcm (1, 5) // 5
, lcm (3, 4) // 12
, lcm (23, 18) // 414
)
Now we have minmax
. Unique to this implementation is that it finds the min and the max using only a single traversal of the input array -
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...rest ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( rest
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
console.log
( minmax ([ 3, 4, 2, 5, 1 ]) // [ 1, 5 ]
, minmax ([ 1, 5 ]) // [ 1, 5 ]
, minmax ([ 5, 1 ]) // [ 1, 5 ]
, minmax ([ 9 ]) // [ 9, 9 ]
, minmax () // [ Infinity, -Infinity ]
)
By default minmax
returns a list
of the min and max values. We can plug the min and max directly into a range
function, which might be more useful to us, as we'll see later -
const range = (m, n) =>
m > n
?
: [ m, ... range (m + 1, n ) ]
console.log
( minmax ([ 3, 4, 2, 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 1, 5 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 9 ], range) // [ 9 ]
, minmax (, range) //
)
Now that we can find the min and max of the input, create a range between the two, all that's left is calculating the lcm
of the values in the range. Taking many values and reducing them to a single value is done with .reduce -
console.log
( minmax ([1, 5], range) .reduce (lcm, 1) // 60
, minmax ([5, 1], range) .reduce (lcm, 1) // 60
)
Wrap that up in a function and we're done -
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
Verify the result in your own browser below -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...xs ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( xs
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
const range = (m, n) =>
m > n
?
: [ m, ... range (m + 1, n ) ]
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
extra
Above, minmax
is defined using continuation passing style. We save extra computation by passing range
as the specified continuation (then
). However, we can call minmax
without specifying a continuation and spread (...
) the intermediate value to range
. Either program might make more sense to you. The result is the same -
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
same pig, different farm
smallestCommons
is basically just a reduction over the range[min,max]
- @Carcigenicate
Hopefully it helps to see the same result from multiple approaches :D
sourface
Some people will despise the above implementation of minmax
regardless of its elegance and flexibility. Now that we maybe understand reducing a little better, we can show how minmax
might be better implemented using direct style -
const minmax = xs =>
xs .reduce
( ([ min, max ], x) =>
[ Math.min (min, x)
, Math.max (max, x)
]
, [ Infinity, -Infinity ]
)
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1) // direct style now required here
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
console.log
( lcm (1, 5) // 5
, lcm (3, 4) // 12
, lcm (23, 18) // 414
)
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
console.log
( lcm (1, 5) // 5
, lcm (3, 4) // 12
, lcm (23, 18) // 414
)
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...xs ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( xs
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
const range = (m, n) =>
m > n
?
: [ m, ... range (m + 1, n ) ]
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...xs ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( xs
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
const range = (m, n) =>
m > n
?
: [ m, ... range (m + 1, n ) ]
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
edited Nov 15 '18 at 18:31
answered Nov 15 '18 at 17:56
user633183user633183
71k21141180
71k21141180
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53324572%2fcalling-and-passing-nested-functions-in-javascript%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Does LCM = lowest common multiple? If so, it's not clear why the LCM of
[5, 1]
is60
.– Mark Meyer
Nov 15 '18 at 17:09
(LCM = Least Common Multiple) The LCM of 5 and 1 is 5. The LCM of 1 and 13 is 13. The LCM of 23 and 18 is 414. I'm a little confused as what you're after. There is no need to nest the declarations of these functions. They will run faster if you extract the
scm
function and just call it inside ofsmallestCommons
. ThesmallestCommon
function is completely extraneous considering all it does is definescm
and return an invocation ofscm
.– Kyle Richardson
Nov 15 '18 at 17:13