可以在没有辅助方法的情况下执行链式阶乘方法
Possible to do a chained factorial method without a helper method
我在看看是否可以按如下方式编写阶乘方法:
class InlineMath {
constructor(x) {
this.x = x
}
minus(y) {
this.x -= y;
return this;
}
times(y) {
this.x *= y;
return this;
}
factorial(n) {
if (n == 1) {
return this;
} else {
this.x = this.times(this.factorial(this.minus(1)));
}
}
}
x = new InlineMath(2);
x.factorial().factorial();
console.log(x);
我知道这是一种完全非标准的方法,但只是想看看这种方法是否可行(即,仅通过副作用)。
但到目前为止,我能弄清楚如何做到这一点的唯一方法是像这样卸载它:
class InlineMath {
constructor(x) {
this.x = x
}
minus(y) {
this.x -= y;
return this;
}
times(y) {
this.x *= y;
return this;
}
factorial() {
this.x = _factorial(this.x);
return this;
}
}
function _factorial(n) {
if (n==1) {
return n;
} else {
return n * _factorial(n-1);
}
}
x = new InlineMath(2);
x.factorial().factorial();
console.log(x);
此处多处错误。
- 不要重新分配
this.x
,保持您的实例不可变。
factorial
方法不应该带参数,它应该使用存储在实例中的值
- 因此,
factorial
的递归调用需要在不同的实例上进行,并且不提供参数
factorial
方法必须始终 return 一个新实例,而不是像您当前的 else
分支一样。
重命名后:
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());
在阶乘公式n * (n-1)!
中,您需要两次值n
。对于可变数学对象,您需要为递归调用克隆它:
class InlineMath {
constructor(x) {
this.x = x
}
clone() {
return new InlineMath(this.x);
}
minus(y) {
this.x -= y;
return this;
}
times(y) {
this.x *= y;
return this;
}
factorial() {
if (this.x > 1)
this.times(this.clone().minus(1).factorial().x);
return this;
}
}
x = new InlineMath(3);
x.factorial().factorial();
console.log(x);
请注意,将公式写成 (n-1)! * n
并不容易:
this.minus(1).factorial().times(this.clone().x)
将无法工作,因为克隆发生得太晚了。我推荐我的另一个答案,它可以避免这种蠕虫病毒……
模块
我建议用普通函数编写您的 math
模块。您可以提供 InlineMath
class 作为普通函数的薄包装。这使得编写普通函数和 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
吃蛋糕也吃
上述方法的一个低估优势是我们的 math
模块有一个双接口。我们可以像上面演示的那样以建议的面向对象的方式使用它,或者我们可以以函数式的方式使用它 -
// main.js
import { plus, times, factorial } from "./math"
console.log(factorial(factorial(3)))
console.log(factorial(times(5,plus(2,1))))
720
1307674368000
唾手可得的果实
如果 math
可以支持非常大的数字,也许会很酷?
// 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
演示
运行 下面的代码片段在您自己的浏览器中验证结果 -
// 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())
我希望这只是一个概念验证,您永远不会打算使用这样的代码。但是对您的代码进行简单的更改将实现此“通过副作用”:
class InlineMath {
constructor(x) {
this.x = x
}
minus(y) {
this.x -= y;
return this;
}
times(y) {
this.x *= y;
return this;
}
factorial() {
if (this.x <= 1) {
this.x = 1;
} else {
this.x *= this.minus(1).factorial().x
}
return this;
}
}
const x = new InlineMath(3);
x.factorial().factorial();
console.log(x);
我在看看是否可以按如下方式编写阶乘方法:
class InlineMath {
constructor(x) {
this.x = x
}
minus(y) {
this.x -= y;
return this;
}
times(y) {
this.x *= y;
return this;
}
factorial(n) {
if (n == 1) {
return this;
} else {
this.x = this.times(this.factorial(this.minus(1)));
}
}
}
x = new InlineMath(2);
x.factorial().factorial();
console.log(x);
我知道这是一种完全非标准的方法,但只是想看看这种方法是否可行(即,仅通过副作用)。
但到目前为止,我能弄清楚如何做到这一点的唯一方法是像这样卸载它:
class InlineMath {
constructor(x) {
this.x = x
}
minus(y) {
this.x -= y;
return this;
}
times(y) {
this.x *= y;
return this;
}
factorial() {
this.x = _factorial(this.x);
return this;
}
}
function _factorial(n) {
if (n==1) {
return n;
} else {
return n * _factorial(n-1);
}
}
x = new InlineMath(2);
x.factorial().factorial();
console.log(x);
此处多处错误。
- 不要重新分配
this.x
,保持您的实例不可变。 factorial
方法不应该带参数,它应该使用存储在实例中的值- 因此,
factorial
的递归调用需要在不同的实例上进行,并且不提供参数 factorial
方法必须始终 return 一个新实例,而不是像您当前的else
分支一样。
重命名后:
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());
在阶乘公式n * (n-1)!
中,您需要两次值n
。对于可变数学对象,您需要为递归调用克隆它:
class InlineMath {
constructor(x) {
this.x = x
}
clone() {
return new InlineMath(this.x);
}
minus(y) {
this.x -= y;
return this;
}
times(y) {
this.x *= y;
return this;
}
factorial() {
if (this.x > 1)
this.times(this.clone().minus(1).factorial().x);
return this;
}
}
x = new InlineMath(3);
x.factorial().factorial();
console.log(x);
请注意,将公式写成 (n-1)! * n
并不容易:
this.minus(1).factorial().times(this.clone().x)
将无法工作,因为克隆发生得太晚了。我推荐我的另一个答案,它可以避免这种蠕虫病毒……
模块
我建议用普通函数编写您的 math
模块。您可以提供 InlineMath
class 作为普通函数的薄包装。这使得编写普通函数和 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
吃蛋糕也吃
上述方法的一个低估优势是我们的 math
模块有一个双接口。我们可以像上面演示的那样以建议的面向对象的方式使用它,或者我们可以以函数式的方式使用它 -
// main.js
import { plus, times, factorial } from "./math"
console.log(factorial(factorial(3)))
console.log(factorial(times(5,plus(2,1))))
720
1307674368000
唾手可得的果实
如果 math
可以支持非常大的数字,也许会很酷?
// 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
演示
运行 下面的代码片段在您自己的浏览器中验证结果 -
// 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())
我希望这只是一个概念验证,您永远不会打算使用这样的代码。但是对您的代码进行简单的更改将实现此“通过副作用”:
class InlineMath {
constructor(x) {
this.x = x
}
minus(y) {
this.x -= y;
return this;
}
times(y) {
this.x *= y;
return this;
}
factorial() {
if (this.x <= 1) {
this.x = 1;
} else {
this.x *= this.minus(1).factorial().x
}
return this;
}
}
const x = new InlineMath(3);
x.factorial().factorial();
console.log(x);