Possible to do a chained factorial method without a helper method
modules
I would suggest writing your math
module with ordinary functions. You can provide an InlineMath
class as a thin wrapper around the plain functions. This makes it easier to write both the ordinary functions and the class -
// math.js
const minus = (a, b) => a - b
const plus = (a, b) => a + b
const times = (a, b) => a * b
const factorial = a => a == 0 ? 1 : times(a, factorial(minus(a, 1)))
const math = a => new InlineMath(a)
class InlineMath {
constructor(t) { this.t = t }
factorial() { return math(factorial(this.t)) }
minus(x) { return math(minus(this.t, x)) }
plus(x) { return math(plus(this.t, x)) }
times(x) { return math(times(this.t, x)) }
toNumber() { return this.t }
}
export { math, minus, plus, times, factorial }
// main.js
import { math } from "./math.js"
console.log(math(3).factorial().factorial().toNumber())
console.log(math(1).plus(2).times(5).factorial().toNumber())
720
1307674368000
have your cake and eat it too
One understated advantage of the approach above is that we have a dual interface for our math
module. We can use it in the proposed object-oriented way as demonstrated above, or we can use it with a functional approach -
// main.js
import { plus, times, factorial } from "./math"
console.log(factorial(factorial(3)))
console.log(factorial(times(5,plus(2,1))))
720
1307674368000
low-hanging fruit
Maybe it would be cool if math
could support really big numbers?
// math.js
const minus = (a, b) => BigInt(a) - BigInt(b)
const plus = (a, b) => BigInt(a) + BigInt(b)
const times = (a, b) => BigInt(a) * BigInt(b)
const factorial = a => /* unchanged */
const math = a => /* unchanged */
class InlineMath {
/* ... */
toString() { return this.t.toString() }
}
export { math, minus, plus, times, factorial }
// main.js
import { math } from "./math.js"
console.log(math(5).factorial().factorial().toNumber())
(5!)! = 120! =
6689502913449127057588118054090372586752746333138029810295671352301633557244962989366874165271984981308157637893214090552534408589408121859898481114389650005964960521256960000000000000000000000000000
demo
Run the snippet below to verify the result of in your own browser -
// math.js module
const minus = (a, b) => BigInt(a) - BigInt(b)
const plus = (a, b) => BigInt(a) + BigInt(b)
const times = (a, b) => BigInt(a) * BigInt(b)
const factorial = a => a == 0 ? 1 : times(a, factorial(minus(a, 1)))
const math = a => new InlineMath(a)
class InlineMath {
constructor(t) { this.t = t }
factorial() { return math(factorial(this.t)) }
minus(x) { return math(minus(this.t, x)) }
plus(x) { return math(plus(this.t, x)) }
times(x) { return math(times(this.t, x)) }
toNumber() { return this.t.toString() }
}
// main.js
console.log(math(5).factorial().factorial().toNumber())
Multiple mistakes here.
- Don't reassign
this.x
, keep your instances immutable. - the
factorial
method should not take a parameter, it should use the value stored in the instance - consequently, the recursive call of
factorial
needs to be made on a different instance, and not be given an argument - the
factorial
method must always return a new instance, not nothing like your currentelse
branch.
With some renaming:
class InlineNumber {
constructor(n) {
this.n = n
}
factorial() {
if (this.n == 1) {
// return 1
return this;
} else {
// return n * (n-1)!
return this.times(this.minus(new InlineNumber(1)).factorial());
}
}
minus(subtrahend) {
return new InlineNumber(this.n - subtrahend.n);
}
times(multiplicand) {
return new InlineNumber(this.n * multiplicand.n);
}
valueOf() {
return this.n;
}
}
const x = new InlineNumber(3);
console.log(x.factorial().factorial());