recursion iteration and tail calls in js - Lee-hyuna/33-js-concepts-kr GitHub Wiki
JSμ μ¬κ·, λ°λ³΅ κ·Έλ¦¬κ³ κΌ¬λ¦¬ νΈμΆ (tail call)
μ¬κ·μ κ°μ₯ νμ€ μλ μ£Όμ΄μ§ μ«μλ₯Ό 1λΆν° nκΉμ§ λͺ¨λ κ³±νλ n! = n * (n - 1) * ... * 1
ν©ν λ¦¬μΌ ν¨μ μ΄λ€.
function factorial(n) {
if (n === 0) {
return 1;
}
return n * factorial(n - 1);
}
μμ λνλΈ μμ λ ν©ν λ¦¬μΌ ν¨μμ κ°μ₯ νλ²ν ꡬνμ΄λ€.
n = 6
μΌ λ μμ μμ κ° μ΄λ»κ² λμνλμ§ μ΄ν΄λ³΄μ,
- factorial(6)
- 6 * factorial(5)
- 5 * factorial (4)
- 4 * factorial(3)
- 3 * factorial(2)
- 2 * factorial(1)
- 1 * factorial(0)
- 1
- (resuming previous execution) 1 * 1 = 1
- 1 * factorial(0)
- (resumingβ¦) 2 * 1 = 2
- 2 * factorial(1)
- (β¦) 3 * 2 = 6
- 3 * factorial(2)
- β¦ 4 * 6 = 24
- 4 * factorial(3)
- 5 * 24 = 120
- 5 * factorial (4)
- 6 * 120 = 720
- 6 * factorial(5)
- factorial(6) = 720
μμΌλ‘ μΌμ΄λ μμ λ€μ μ΄ν΄ν μ μλλ‘ λ¬΄μ¨ μΌμ΄ μΌμ΄λκ³ μλμ§ μ μ€νκ² λ΄μΌνλ€.
ν¨μλ₯Ό νΈμΆνλ©΄ ν λ²μ μ¬λ¬ κ°μ§ μΌμ΄ λ°μνλ€. ν¨μλ₯Ό νΈμΆ ν ν λμ κ°μΌνλ μμΉλ νμ¬ νλ μ(μ½ μ€νμ)μ μ 보 (μ : n κ°)μ ν¨κ» μ μ₯λ©λλ€. κ·Έλ° λ€μ μ ν¨μλ₯Ό μν 곡κ°μ΄ ν λΉλκ³ μ νλ μμ΄ μμ±λλ€.
κ³μν΄μ νλ μμ μμ μ¬λ¦° λ€μ ν΄λΉ μ€νμ νμ΄ ν¨μ νΈμΆμ λ°ν λ κ°μΌλ‘ λ°κΎΌλ€.
μ£Όλͺ©ν΄μΌ ν λ λ€λ₯Έ μ¬νμ ν¨μμ μν΄ μμ± λ νλ‘μΈμ€μ λͺ¨μμ΄λ€. μ΄ λͺ¨μμ μ¬κ· λΌκ³ λΆλ₯΄λ©΄ λλΌμ§ μμ κ² μ΄λ€. λ°λΌμ μ¬κ· νλ‘μΈμ€κ° μλ€. λμ리μ¬
ν©ν 리μΌμ λ λ²μ§Έ ꡬνμ μ΄ν΄λ³΄μ.
function factorial(n, res) {
if (n === 0) {
return res;
}
return factorial(n - 1, res * n);
}
λ΄λΆ ν¨μλ₯Ό μ μν¨μΌλ‘μ¨ ν¨μλ₯Ό μ’ λ μΊ‘μνν μ μλ€.
function factorial(n) {
function inner_factorial(n, res) {
if (n === 0) {
return res;
}
return inner_factorial(n - 1, res * n);
}
return inner_factorial(n, 1);
}
μ΄ ν¨μκ° μ΄λ»κ² μ€νλλμ§ μ΄ν΄λ³΄μ.
- factorial(6)
- λ΄λΆ μ΅λͺ
ν¨μ(iaf) λ(n = 6, res = 1)
- iaf(5, 1 * 6)
- iaf(4, 6 * 5)
- iaf(3, 30 * 4)
- iaf(2, 120 * 3)
- iaf(1, 360 * 2)
- iaf(0, 720)
- 720
- 720
- iaf(0, 720)
- 720
- iaf(1, 360 * 2)
- 720
- iaf(2, 120 * 3)
- 720
- iaf(3, 30 * 4)
- 720
- iaf(4, 6 * 5)
- 720
- iaf(5, 1 * 6)
- iaf (6, 1) = 720
- λ΄λΆ μ΅λͺ
ν¨μ(iaf) λ(n = 6, res = 1)
- factorial(6) = 720
μ€νμ νκ³ λμ κ³μ°μ μν ν νμκ° μλ€λ κ²μ μ μ μλ€. λ°©κΈ κ°μ λ°ννλ€. κ·Έλ¬λ κ·μΉμ λ°λΌ 체μΈμμ λμ€μ μ¬μ©νμ§ μλλΌλ μνλ₯Ό μ€ν νλ μμΌλ‘ μ μ₯ν΄μΌνλ€.
κ·Έλ¬λ κ·μΉμ λͺ¨λ μΈμ΄μ μ μ©λλ κ²μ μλλ€. μ€μ λ‘, Schemeμμλ μ΄λ¬ν 체μΈμ tail call μ΅μ νλ‘ μ΅μ νν΄μ¬νλ€. μ΄λ₯Ό ν΅ν΄ μ€νμ λΆνμν νλ μμ΄ μ±μμ§μ§ μλλ€. μ°λ¦¬μ μ μμ λ λ€μκ³Ό κ°μ΄ λ³΄μΌ κ²μ΄λ€.
- factorial(6)
- iaf(6, 1)
- iaf(5, 6)
- iaf(4, 30)
- iaf(3, 120)
- iaf(2, 360)
- iaf(1, 720)
- iaf(0, 720)
- 720
κ²°κ³Όμ μΌλ‘ λμ°νκ² λ³΄μΈλ€.
μ¦, μ¬κ·λ₯Ό μ¬μ©νλλΌλ λ°λ³΅μ μΈ νλ‘μΈμ€κ° μλ€.
μ’μ μμμ ES6μ ν¨μμ΄λ€. μ¬κ· νΈμΆμ΄ ν
μΌ μμΉμ μκ³ ν¨μμ strict λͺ¨λκ° μμΌλ©΄ ν
μΌ νΈμΆ μ΅μ νκ° μμλκ³ maximum stack size exceeded
μ€λ₯κ° λ°μνμ§ μλλ€.
μ λ°μ΄νΈ 2017 λ 12 μ 1 μΌ : ν μΌ μ½ μ΅μ ν κΈ°λ₯μ΄μλ μ μΌν μ£Όμ λΈλΌμ°μ λ Safariμ΄λ€. V8μ μν₯μ μ£Όμ§λ§ 2 κ° μμ§ λμ€μ§ μμ μ΄μ λ μλ 3κ°μ§μ΄λ€.
1: https://kangax.github.io/compat-table/es6/#test-proper_tail_calls_(tail_call_optimisation)
2: https://bugs.chromium.org/p/v8/issues/detail?id=4698
3: https://v8project.blogspot.com/2016/04/es6-es7-and-beyond.html