ã¯ããã«
ES6 (EcmaScript 6)ã詊ãããšãBabelã®ããã¥ã¡ã³ããèªãã§ãããšãããæ«å°ŸåŒã³åºãïŒTail CallïŒã®æé©åãããŠããããšã«ã³ã£ãããå ¬åŒãªãªãŒã¹ïŒ2015幎6æïŒããïŒã¶æããŸãçµã£ãŠã¯ããŸãããES6ãæ«å°ŸåŒã³åºãæé©åã仿§ãšããŠãµããŒãããŠããããšãããããç¥ããŸããã
çŸç¶ã§æ«å°ŸåŒã³åºãæé©åããµããŒãããŠãããã©ãŠã¶ã¯ãªãïŒãã©ãŠã¶ãaltJSãªã©ã®ES6äºæè¡šãåç §ïŒãå¯äžãES6ããES5ãžã®ãã©ã³ã¹ãã€ã©ã§ããBabelã®ã¿ãéšåçïŒçŽæ¥çãªæ«å°Ÿååž°ã®ã¿ïŒã§ã¯ãããªãããµããŒãããŠããããã§ããã
ä»åã®èšäºã§ã¯ãæ¥ããES6æä»£ïŒããŸããã®æã¯ãããŸããïŒã«åããŠãæ«å°Ÿååž°ãšãã®æé©åã«ã€ããŠç°¡åã«è§£èª¬ããäžã§ãBabelãå©çšããŠå®éã«JavaScriptã§ã®æ«å°Ÿååž°ã®æé©åãå®éšããŠã¿ãããšæããŸãã
ãã£ããæŠèŠ
- ååž°é¢æ° ã¯é¢æ°åŒã³åºãã®éæ°ãæ·±ããªãããããš ã¹ã¿ãã¯ãªãŒããŒãã㌠ãçºçããåé¡ããããŸãã
- æ«å°ŸåŒã³åºãã®ã³ãŒãæé©å æè¡ã«ãããååž°é¢æ°ã æ«å°Ÿååž° ã«å€æãããšãã®åé¡ã¯è§£æ±ºã§ããŸãã
- ãã ããã³ãŒãæé©åã¯ããã°ã©ã ã®å®è¡ç°å¢ããµããŒãããŠããªããšãã®æ©æµãåããããŸããã
- 次äžä»£JavaScriptã®ä»æ§ãšãªãES6ã§ã¯ æ«å°ŸåŒã³åºãã®ã³ãŒãæé©åã仿§åãããŠããŸãã
- ãã®ãããåãã©ãŠã¶ãnode.jsãªã©ã®å®è¡ç°å¢ã¯ãES6ã«æºæ ããã«ã¯ã³ãŒãæé©åãå®è£ ããå¿ èŠããããŸãã
- çŸæç¹ïŒ2015/10ïŒã§æé©åãå®è£ ããŠãããã©ãŠã¶ïŒå®è¡ç°å¢ïŒã¯ãããŸããã
- ãã ããES6ããES5ãžã®ãã©ã³ã¹ãã€ã©ã§ãã Babel ã¯å¶éä»ããªããæé©åãå®çŸããŠããŸãã
- Babelã¯ES6ã®æ«å°Ÿååž°ã®ã³ãŒããéåžžã®ã«ãŒãïŒwhileãªã©ïŒã«ããã³ãŒãã«å€æããŸãã
ååž°é¢æ°ã®åé¡
ååž°é¢æ°
èªåèªèº«ãåŒã³åºã颿°ã ååž°é¢æ°ïŒrecursive functionïŒ ãšåŒã³ãŸããããããäŸã§ãããäžããããæ°nã®éä¹ïŒ1ããnãŸã§ã®ãã¹ãŠã®æ°å€ã®ç©ïŒãèšç®ãã以äžã®é¢æ°factorialã¯ååž°é¢æ°ã§ãã
// éä¹ãèšç®ãã颿°
function factorial(n) {
if (n === 0) {
return 1;
}
return n * factorial(n - 1); // èªåèªèº«ãåŒã³åºã
}
console.log(factorial(3)); // 6ãšãªã
ã¹ã¿ãã¯ãªãŒããŒãããŒ
ååž°é¢æ°ã¯èªåèªèº«ãååž°çã«åŒã³åºãããã颿°ã®åŒã³åºãéå±€ãæ·±ããªããã¡ã§ããå
éšçã«ã¯é¢æ°ã®åŒã³åºãããšã«ã¡ã¢ãªé åãæ¶è²»ããããããåŒã³åºãéå±€ãæ·±ããªãããããšå®è¡æãšã©ãŒãçºçããå ŽåããããŸããå®éãäžèšã®factorial颿°ãæå
ã®node.jsïŒv0.12.6ïŒäžã§å®è¡ãããšãããåŒæ°ã100000ã§ãšã©ãŒã«ãªããŸãããïŒInfinityã¯æ°å€ã®äžéãè¶
ããããã§ããä»åã®ãšã©ãŒãšã¯é¢ä¿ãããŸãããïŒ
> function factorial(n) {
... if (n === 0) {
..... return 1;
..... }
... return n * factorial(n - 1);
... }
undefined
> factorial(100);
9.33262154439441e+157
> factorial(1000);
Infinity
> factorial(10000);
Infinity
> factorial(100000);
RangeError: Maximum call stack size exceeded
at factorial (repl)
at factorial (repl:5:24)
at factorial (repl:5:24)
at factorial (repl:5:24)
at factorial (repl:5:24)
at factorial (repl:5:24)
at factorial (repl:5:24)
at factorial (repl:5:24)
at factorial (repl:5:24)
at factorial (repl:5:24)
>
factorial(100000)ã®çµæãšããŠã"RangeError: Maximum call stack size exceeded"ïŒã¹ã¿ãã¯ã®äžéãè¶
ãããïŒïŒãšãããŸããããããã¯é¢æ°ã®åŒã³åºãéå±€ãäžéãè¶
ããããšã衚ãå®è¡ãšã©ãŒã§ãããã®ãããªãšã©ãŒãäžè¬çã« ã¹ã¿ãã¯ãªãŒããŒãã㌠ãšåŒã³ãŸããããã°ã©ãã³ã°èšèªã«é¢ä¿ãªããããã°ã©ããªãã°äžåºŠã¯ééããããšããããšã©ãŒã§ãããã
è§£æ±ºæ¹æ³ã¯ïŒ
äžã€ã®æ¹æ³ã¯ãååž°ãéåžžã®ã«ãŒãã«æžãæããããšã§ãã以äžã¯ãforã«ãŒãã䜿çšããfactorialã®å®è£
ã§ãããã®é¢æ°ã¯åŒæ°ã®å€§ããã«ãããããã颿°ã®åŒã³åºãéå±€ã¯äžå®ïŒïŒã€ã ãïŒãªã®ã§ãã¹ã¿ãã¯ãªãŒããŒãããŒã¯çºçããŸããã
function factorial(n) {
var result = 1;
for (var i = 1; i <= n; i++) {
result = result * i;
}
return result;
}
å®éãåŒæ°100000ã§å®è¡ããŠã以äžã®ããã«ã¹ã¿ãã¯ãªãŒããŒãããŒã¯çºçããŸããã
> function factorial(n) {
... var result = 1;
... for (var i = 1; i <= n; i++) {
..... result = result * i;
..... }
... return result;
... }
undefined
> factorial(100000);
Infinity
>
çµå±ååž°é¢æ°ã£ãŠäœ¿ããªãã®ïŒ
ãããŸã§ã®JavaScriptã«å¯ŸããçããšããŠã¯ããã¯ããæ³šæããŠäœ¿çšããªããšã ãã§ããã ãšãªãã§ããããäžèšã®ãããªåé¡ãçºçãããããååž°ãããŸãã«ãæ·±ããªããªãããã«æ³šæãããªã©ãéå®çãªç¶æ³ã§ããå©çšã§ããŸããã§ããã
次äžä»£ã®JavaScriptïŒES6ïŒã«å¯ŸããçããšããŠã¯ãããããããããªããšã¯ãããŸãããæ«å°Ÿååž°ã«å€æããã°ããã®ã§ããã ãšãªãã§ããããååž°é¢æ°ã¯ æ«å°Ÿååž° ãšåŒã°ããç¹æ®ãªåœ¢ã®ååž°é¢æ°ã«æžãæããããšãã§ããŸããæ«å°Ÿååž°ã«ãããšã æ«å°ŸåŒã³åºãæé©å ãšåŒã°ããã³ãŒãæé©åæè¡ã®æ©æµãåããããããã«ãªããŸãããã®ã³ãŒãæé©åã®æè¡ã«ãããäžèšã®ãããªã¹ã¿ãã¯ãªãŒããŒãããŒã¯çºçããªããªããŸããES6ã¯ä»æ§ãšããŠãJavaScriptã®å®è¡ç°å¢åŽã«æ«å°ŸåŒã³åºãæé©åãèŠæ±ããŠãããããES6ã«æºæ ãããã©ãŠã¶ãå®è¡ç°å¢ã§ããã°æ«å°Ÿååž°ãå©çšããã°ããã®ã§ãã
ã§ã¯ã以éã§ã¯æ«å°Ÿååž°ãæ«å°ŸåŒã³åºãæé©åæè¡ã«ã€ããŠè©³ããã¿ãŠãããŸãããã
æ«å°ŸåŒã³åºããšæ«å°ŸåŒã³åºãæé©å
æ«å°ŸåŒã³åºã
ãã颿°fããå¥ã®é¢æ°gãåŒã³åºããšããŸããgã®åŒã³åºããfã®ãªã¿ãŒã³åã®æåŸã®åŠçã§ãããšããgã®é¢æ°åŒã³åºãã æ«å°ŸåŒã³åºãïŒtail callïŒ ãšåŒã³ãŸãã
äŸãã°ã次ã®é¢æ°fã«ãããŠã颿°gã®å®è¡åŸã«ãã®çµæãfã¯ãªã¿ãŒã³ããã ããªã®ã§ãgã®åŒã³åºãã¯æ«å°ŸåŒã³åºããšãªããŸãã
function f() {
return g(); // g()ã¯æ«å°ŸåŒã³åºã
}
以äžã®gããã³hã®åŒã³åºããæ«å°ŸåŒã³åºããšãªããŸããããããbã®åŒã³åºãåŸã«fã®åŠçãç¶ããããbã®åŒã³åºãã¯æ«å°ŸåŒã³åºãã§ã¯ãªããŸããã
function f() {
if (b()) { // b()ã¯æ«å°ŸåŒã³åºãã§ã¯ãªã
return g(); // g()ã¯æ«å°ŸåŒã³åºã
}
else {
return h(); // h()ã¯æ«å°ŸåŒã³åºã
}
}
以äžã®äŸã§ã¯ããœãŒã¹ã³ãŒãäžãhã®åŒã³åºãã¯fã®æåŸã«ãããŸãããæ«å°ŸåŒã³åºãã§ã¯ãããŸããããªããªããhã®åŒã³åºãåŸã«+ã«ããå ç®åŠçãç¶ãããã§ãã
function f() {
return g() + h(); // h()ã¯æ«å°ŸåŒã³åºãã§ã¯ãªããåœç¶ãªããg()ãæ«å°ŸåŒã³åºãã§ã¯ãªãã
}
æ«å°ŸåŒã³åºãæé©å
ã³ãŒã«ã¹ã¿ãã¯
éåžžã®ããã°ã©ã ã®å®è¡ã¢ãã«ã§ã¯ã颿°ãåŒã³åºããšã颿°èªèº«ã®ããŒã«ã«å€æ°ïŒåŒæ°ã屿倿°ïŒãæ»ãå æ å ±ãä¿æããã¹ã¿ãã¯ãã¬ãŒã ïŒã¢ã¯ãã£ããŒã·ã§ã³ã¬ã³ãŒãïŒãçæãããŠã³ãŒã«ã¹ã¿ãã¯ãšåŒã°ããã¹ã¿ãã¯ã«pushãããŸãã颿°ã¯ã¹ã¿ãã¯ãã¬ãŒã ã«èšç®éäžã®å€ãä¿æãã€ã€åŠçãç¶ããŸãã颿°ã®å®è¡ãçµãããšå¯Ÿå¿ããã¹ã¿ãã¯ãã¬ãŒã ãpopãããŠåŒã³åºãå ã®ã¹ã¿ãã¯ãã¬ãŒã ã«åŸ©åž°ããåŒã³åºãå 颿°ã®å®è¡ãåéãããŸãã
以äžã®ã³ãŒãã顿ãšããŠãã³ãŒã«ã¹ã¿ãã¯ã®åããã·ãã¥ã¬ãŒã·ã§ã³ããŠã¿ãŸãããã
function squareSum(x) {
var xs = square(x); //(A)
var result = sum(xs); //(B)
return result; //(C)
}
function square(n) {
return n * n;
}
function sum(n) {
return n + n;
}
//çµæã¯8
squareSum(2); //(X)
衚èš
以äžã§ã¯ã颿°fã®ã¹ã¿ãã¯ãã¬ãŒã ãf:{x:1, y:2}:returnTo:æ»ãå
ã®äœçœ®ã§è¡šããŸããããã§ãxãšyã¯fã®ããŒã«ã«å€æ°ïŒåŒæ°ãå«ãïŒãšããããããå€1ãš2ãä¿æããŠãããã®ãšããŸããf颿°ã®çµäºæã®æ»ãå
ã¯returnToã衚ããã®ãšããŸãã
ã·ãã¥ã¬ãŒã·ã§ã³
ããŠãããã°ã©ã ã®éå§æã®ã¹ã¿ãã¯ãã¬ãŒã ã¯ç©ºã§ããïŒXïŒã®äœçœ®ã§squareSum颿°ãåŒæ°2ã§åŒã³åºãããçŽåŸã¯ãã³ãŒã«ã¹ã¿ãã¯ã«squareSumã®ã¹ã¿ãã¯ãã¬ãŒã ãpushãããŸããããã§ã屿倿°xsãšresultã¯ãŸã å€ãèšå®ãããŠããŸãããæ»ãå
ã«ã¯äœçœ®(X)ãèšå®ãããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| squreSum:{x:2, xs:undefined, result:undefined}:returnTo:(X) |
次ã«ã(A)ã§suqare颿°ãåŒæ°2(=x)ã§åŒã³åºãããŸããã³ãŒã«ã¹ã¿ãã¯ã«ã¯åŒæ°nã2ã§åæåãããã¹ã¿ãã¯ãã¬ãŒã ãpushãããŸãã颿°çµäºåŸã«æ»ãå
ã¯(A)ãèšå®ãããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| square:{n:2}:returnTo:(A) |
| squreSum:{x:2, xs:undefined, result:undefined}:returnTo:(X) |
颿°squareã¯nã®äºä¹ãèšç®ããåŸãåŒã³åºãå
ã®squareSumã«æ»ããŸããããã§ãsquareã®ã¹ã¿ãã¯ãã¬ãŒã ã¯popãããŠãåŒã³åºãå
ã¹ã¿ãã¯ãã¬ãŒã ã®xsã«ã¯squareã®èšç®çµæ4ã代å
¥ãããŸããreturnToã«èšå®ãããŠãã(A)ã®äœçœ®ããå®è¡ãåéãããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| squreSum:{x:2, xs:4, result:undefined}:returnTo(X) |
次ã«ãäœçœ®(B)ã§sum颿°ãåŒæ°4(=xs)ã§åŒã³åºãããŸãããã®ãšããã³ãŒã«ã¹ã¿ãã¯ã¯æ¬¡ã®ããã«ãªããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| sum:{n:4}:returnTo:(B) |
| squreSum:{x:2, xs:4, result:undefined}:returnTo(X) |
颿°sumã®å®è¡ãçµäºãããšãsumã®ã¹ã¿ãã¯ãã¬ãŒã ã¯popãããŸããããã§ãresultã®å€ã¯sumã®å®è¡çµæã代å
¥ãããŸããreturnToã«èšå®ãããŠãã(B)ã®äœçœ®ãããsquareSumã®å®è¡ãåéãããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| squreSum:{x:2, xs:4, result:8}:returnTo(X) |
æåŸã«squareSumã¯resultã®å€8ããªã¿ãŒã³ããŠããã°ã©ã ã¯äœçœ®(X)ã«æ»ã£ãŠçµäºããŸããããã§ãã³ãŒã«ã¹ã¿ãã¯ã¯ç©ºã«ãªããŸãã
æ«å°ŸåŒã³åºãã®é€å»
äžèšã®squareSum颿°ã¯ãã¹ã¿ãã¯ãã¬ãŒã ã«èšç®éäžã®å€ïŒxsãresultïŒãä¿æããŠå®è¡ãç¶ããŸãããã®ããã«ãã¹ã¿ãã¯ãã¬ãŒã ã¯é¢æ°ã®å®è¡éäžã®å€ãä¿æããäžæé åãšããŠã®åœ¹å²ãæã¡ãŸãããååž°é¢æ°ã®äŸã§æ¢ã«ã¿ãããã«ã颿°åŒã³åºãéå±€ãããŸãã«ãæ·±ããªããšã¹ã¿ãã¯ãã¬ãŒã æ°ã倧ãããªããã¡ã¢ãªé åãé£ãã€ã¶ããŠããŸãããšããããŸããäžèŠãªã¹ã¿ãã¯ãã¬ãŒã ã®çæã¯ã§ããã°é¿ããããšããã§ãã
ã¹ã¿ãã¯ãã¬ãŒã ã¯é¢æ°ã®èšç®éäžã®å€ãä¿æããã®ã«å¿
èŠã§ãããèšãæãããšãèšç®éäžã®å€ããã以äžäœ¿çšãããªãã®ã§ããã°ãã¹ã¿ãã¯ãã¬ãŒã ãäžèŠãšããããšã«ãªããŸããããã§ã颿°ã®æ«å°ŸåŒã³åºãã«çç®ããŠã¿ãŸãããããã颿°fãå¥ã®é¢æ°gãæ«å°ŸåŒã³åºãããŠãããšããfã®çµæïŒãªã¿ãŒã³å€ïŒã¯gã®çµæãã®ãã®ã§ããã€ãŸããgã®åŒã³åºãåŸã«fã®ã¹ã¿ãã¯ãã¬ãŒã ã¯äœ¿çšãããŸããããããã£ãŠãgã®åŒã³åºãæã«ã¹ã¿ãã¯ãã¬ãŒã ãæ°ãã«çæããã®ã§ã¯ãªããfã®ã¹ã¿ãã¯ãã¬ãŒã ãgã®ã¹ã¿ãã¯ãã¬ãŒã ãšããŠåå©çšããããšãå¯èœã§ããããã æ«å°ŸåŒã³åºãã®é€å»ïŒtail call eliminationïŒ ãšåŒã³ãŸããã³ã³ãã€ã©ãå®è¡ç°å¢ãè¡ãæ«å°ŸåŒã³åºãã®é€å»ã æ«å°ŸåŒã³åºãæé©åïŒtail call optimizationïŒ ãšãããŸãã
以äžã®ç°¡åãªã³ãŒããã¿ãŠãã ãããfooã¯sumãæ«å°ŸåŒã³åºãããŠããŸãã
function foo(x) {
return sum(x, x); // (A)
}
function sum(a, b) {
return a + b;
}
foo(2); // (X)
æ«å°ŸåŒã³åºãã®é€å»ãè¡ããªãã±ãŒã¹
ãã®ã³ãŒãã®ã¹ã¿ãã¯ãã¬ãŒã ã®åããã¿ãŠã¿ãŸãããããŸããæ«å°ŸåŒã³åºãã®é€å»ãè¡ããªãéåžžã®ã±ãŒã¹ã§ãã
äœçœ®(X)ã§fooãåŒã³åºããçŽåŸã¯æ¬¡ã®ããã«ãªããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| foo:{x:2}:returnTo:(X) |
次ã«ã(A)ã®äœçœ®ã§sum颿°ãåŒã³åºããçŽåŸã¯æ¬¡ã®ããã«ãªããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| sum:{a:2, b:2}:returnTo:(A) |
| foo:{x:2}:returnTo:(X) |
颿°sumãçµäºãããšã¹ã¿ãã¯ãã¬ãŒã ãpopãããreturnToã瀺ã(A)ã®äœçœ®ããfooã®é¢æ°ã®å®è¡ãåéãããŸããããã§ãsumã®æ»ãå€ãä¿æããããã®äžæçãªé åãå
éšçã«çæãããŠããã¯ãã§ãããã®äŸã§ã¯_tmp倿°ã«sumã®æ»ãå€ãæ ŒçŽããããšããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| foo:{x:2, _tmp:4}:returnTo:(X) |
æåŸã«fooã¯_tmpã®å€ããªã¿ãŒã³ããŠçµäºããŸãã
æ«å°ŸåŒã³åºãã®é€å»ãè¡ãã±ãŒã¹
次ã«ãæ«å°ŸåŒã³åºãã®é€å»ãè¡ãå Žåã®æåãã¿ãŠã¿ãŸãããã
ãŸããfooã®åŒã³åºãçŽåŸã®ã³ãŒã«ã¹ã¿ãã¯ã¯æ¬¡ã®ããã«ãªããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| foo:{x:2}:returnTo:(X) |
次ã«ã(A)ã§sum颿°ãåŒã³åºããŸããéåžžïŒæ«å°ŸåŒã³åºãã®é€å»ãè¡ããªãå ŽåïŒã¯æ°ããã¹ã¿ãã¯ãã¬ãŒã ãçæãããŠpushãããããšãã§ãããæ«å°ŸåŒã³åºãã®é€å»ãè¡ãå Žåãfooã®ã¹ã¿ãã¯ãã¬ãŒã ãsumã®ã³ãŒã«ã¹ã¿ãã¯ãšããŠåå©çšããŸãããã®ãšããã³ãŒã«ã¹ã¿ãã¯ã¯æ¬¡ã®ããã«ãªããŸããããã§ãfooã®æ»ãå
ãšããŠãsumã®æ»ãå
ïŒXïŒãèšå®ãããããšã«æ³šç®ããŠãã ãããã€ãŸããsumã®ãªã¿ãŒã³å€ïŒå®è¡çµæïŒããã®ãŸãŸfooã®ãªã¿ãŒã³å€ãšãªãã®ã§ãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| sum:{a:2, b:2}:returnTo:(X) |
颿°sumã¯èšç®çµæ4ãreturnToã瀺ãäœçœ®(X)ã«ãªã¿ãŒã³ããŸãã
æ«å°Ÿååž°ãšæ«å°Ÿååž°ã®æé©å
æ«å°Ÿååž°
ååž°é¢æ°ã®ãã¡ãèªåèªèº«ã®åŒã³åºããæ«å°ŸåŒã³åºããšãªã£ãŠããååž°é¢æ°ã æ«å°Ÿååž°ïŒtail recursiveïŒ ãšåŒã³ãŸãã
æ¬èšäºã®æåã«äŸç€ºãã以äžã®éä¹èšç®é¢æ°ã¯èªåèªèº«ãååž°åŒã³åºãããããšã*ã«ããæŒç®ãè¡ã£ãŠãããããæ«å°ŸåŒã³åºãïŒã€ãŸããæ«å°Ÿååž°ïŒã§ã¯ãããŸããã
// éä¹ãèšç®ããååž°é¢æ°ïŒæ«å°Ÿååž°ã§ã¯ãªãïŒ
function factorial(n) {
if (n === 0) {
return 1;
}
return n * factorial(n - 1); // èªåèªèº«ãåŒã³åºããåŸã«ã* ã«ããæŒç®ãè¡ã£ãŠããã®ã§æ«å°ŸåŒã³åºãã§ã¯ãªãã
}
ãã®é¢æ°ããæ«å°Ÿååž°ã«æžãçŽããã³ãŒãã¯ä»¥äžã®ããã«ãªããŸããå
éšé¢æ°factorialTailCallã¯èªåèªèº«ãæ«å°ŸåŒã³åºãããŠããŸãããã€ã³ãã¯ãæŒç®çµæã颿°ã®åŒæ°ãšããŠçޝç©ããŠããšããã§ãã
// éä¹ãèšç®ãã颿°ïŒæ«å°Ÿååž°ããŒãžã§ã³ïŒ
function factorial(n) {
// æ«å°Ÿååž°é¢æ°
function factorialTailCall(n, accum) {
if (n === 0) {
return accum;
}
return factorialTailCall(n - 1, n * accum); // èªåèªèº«ãæ«å°ŸåŒã³åºã
}
var result = factorialTailCall(n, 1); // (Y)
return result;
}
console.log(factorial(3)); // (X)
æ«å°Ÿååž°ã®æé©å
æ«å°Ÿååž°ã¯èªåèªèº«ãæ«å°ŸåŒã³åºãããååž°é¢æ°ã§ããã€ãŸããæ«å°ŸåŒã³åºãã®é€å»ã®ãã¯ããã¯ãå©çšã§ããŸãã
äžèšã®factorialTailCall颿°ãæ«å°ŸåŒã³åºãã®é€å»ã«ããæé©åãã³ã³ãã€ã©ã«ãã£ãŠè¡ãããŠãããšä»®å®ããŸãããããã®ãšããfactorial(3)ãå®è¡ãããšãã®ã³ãŒã«ã¹ã¿ãã¯ã®ç¶æ
é·ç§»ãã¿ãŠã¿ãŸãããã
ãŸããfactorialã®ã¹ã¿ãã¯ãã¬ãŒã ãpushãããŸããresultã®å€ã¯ãŸã undefinedã§ãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| factorial:{n:3, result:undefined}:returnTo(X) |
次ã«ã(Y)ã®äœçœ®ã§ãfactorialTailCall(3, 1)ãåŒã³åºããããããfactorialTailCallã®æ°ããã¹ã¿ãã¯ãã¬ãŒã ãçæãããŠpushãããŸãããã®ãšããnãšaccumã®å€ã¯ããããã3ãš1ã«åæèšå®ãããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| factorialTailCall:{n:3, accum:1}:returnTo(Y) |
| factorial:{n:3, result:undefined}:returnTo(X) |
次ã«ãfactorialTailCallãååž°åŒã³åºããããšãæ°ããã¹ã¿ãã¯ãã¬ãŒã ã¯çæããããæ¢ã«ããã¹ã¿ãã¯ãã¬ãŒã ã®nãšaccumã®å€ãæŽæ°ãããŸãããããŠãfactorialTailCallã®å®è¡ãéå§ãããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| factorialTailCall:{n:2, accum:3}:returnTo(Y) |
| factorial:{n:3, result:undefined}:returnTo(X) |
ããã«ãfactorialTailCallãååž°çã«åŒã³åºãããŸããã¹ã¿ãã¯ãã¬ãŒã ã®nãšaccumã®å€ãæŽæ°ãããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| factorialTailCall:{n:1, accum:6}:returnTo(Y) |
| factorial:{n:3, result:undefined}:returnTo(X) |
æåŸã®ååž°åŒã³åºããå®è¡ãããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| factorialTailCall:{n:0, accum:6}:returnTo(Y) |
| factorial:{n:3, result:undefined}:returnTo(X) |
颿°factorialTailCallã¯accumã®å€6ããªã¿ãŒã³ããŸãããã®ãšããã¹ã¿ãã¯ãã¬ãŒã ã¯popãããŠãäœçœ®(Y)ããfactorial颿°ã®å®è¡ãåéãããŸããresultã¯accumã®å€ãèšå®ãããŸãã
| ã³ãŒã«ã¹ã¿ã㯠|
|---|
| factorial:{n:3, result:6}:returnTo(X) |
颿°factorialã¯resultã®å€ããªã¿ãŒã³ãã(X)ã®äœçœ®ããåŠçãåéããŸãã
äžèšã®ããã«ãæ«å°Ÿååž°é¢æ°factorialTailCallã®ã¹ã¿ãã¯ãã¬ãŒã ã®æ¶è²»æ°ã¯åžžã«ïŒã€ã§ããæ«å°ŸåŒã³åºãæé©åã«ãããæ«å°Ÿååž°ã¯å¹ççã«å®è¡ã§ããããšãçè§£ã§ãããšæããŸãã
JavaScriptã§ã®æ«å°ŸåŒã³åºãæé©å
æ«å°ŸåŒã³åºãæé©åã¯ããã°ã©ãã³ã°ãã¯ããã¯ã§ã¯ãããŸãããã³ã³ãã€ã©ãªã©ã®èšèªåŠçç³»ã«ããã³ãŒãæé©åã®æè¡ã§ããäŸãã°ãJavaã¯ãµããŒãããŠããŸãããåãJVMèšèªã§ãScalaã¯å¶éä»ãã§ãµããŒãããŠããŸããSchemeã¯èšèªã®å®è£ 仿§ãšããŠèŠæ±ããŠããŸãã
JavaScriptã«ã€ããŠã¯ããããŸã§æ«å°ŸåŒã³åºãæé©åã¯å®è¡ç°å¢ã®å®è£ è ã«äŸåããŠããŸãããES6ã§ã¯Schemeãšåãããã«èšèªä»æ§ãšããŠæ«å°ŸåŒã³åºãæé©åãæ±ããŠããŸãããã®ãããä»åŸãåãã©ãŠã¶ã¯ES6ã«æºæ ããããã«æ«å°ŸåŒã³åºãæé©åãå®è£ ããã§ãããããã ããçŸæç¹ã§ã¯æ«å°ŸåŒã³åºãæé©åãå®è£ ããŠãããã©ãŠã¶ã¯ãªãããã§ãïŒãã©ãŠã¶ãaltJSãªã©ã®ES6äºæè¡šãåç §ïŒã
ãã ããåŸè¿°ããBabelãå©çšãããšãJavaScriptã§ãæ«å°Ÿååž°ã®æé©åã®æ©æµãåããããšãã§ããããã«ãªããŸãã
Babelã«ããæ«å°Ÿååž°ã®æé©å
Babelã¯ES6ã®ã³ãŒãããES5ã®ã³ãŒããçæãããã©ã³ã¹ãã€ã©ã®äžçš®ã§ããBabelã§ã¯ãES5ãçæããéçšã§ãæ«å°Ÿååž°ãéåžžã®ã«ãŒãåŠçã«å€æããããšã§ãæ«å°Ÿååž°ã®æé©åãå®çŸããŠããŸãããã ããBabelãå¯èœãªæé©åã«ã¯å¶çŽããããçžäºååž°ïŒä»é²ãåç §ããŠãã ããïŒãªã©ã®è€éãªååž°é¢æ°ã®æé©åã¯ã§ããŸãããèªåèªèº«ãçŽæ¥åŒã³åºãæ«å°Ÿååž°ã®ã¿ãæé©å察象ã§ãã
ã§ã¯ãBabelã«ããæ«å°Ÿååž°ã®æé©åã®å®éšãè¡ã£ãŠã¿ãŸããããæ¬èšäºã§ç޹ä»ããæ«å°Ÿååž°ããŒãžã§ã³ã®ååž°é¢æ°ãåæ²ããŸãã
// éä¹ãèšç®ãã颿°ïŒæ«å°Ÿååž°ããŒãžã§ã³ïŒ
function factorial(n) {
function factorialTailCall(n, accum) {
if (n === 0) {
return accum;
}
return factorialTailCall(n - 1, n * accum);
}
return factorialTailCall(n, 1);
}
ãã®é¢æ°ãBabelã«ããES5ã®ã³ãŒãã«å€æãããšã次ã®ãããªã³ãŒããçæãããŸããä»åã®å€æã¯ãBabelãæäŸããWebãµãŒãã¹ãå©çšããŸããã
function factorial(n) {
function factorialTailCall(_x, _x2) {
var _again = true;
_function: while (_again) {
var n = _x,
accum = _x2;
_again = false;
if (n === 0) {
return accum;
}
_x = n - 1;
_x2 = n * accum;
_again = true;
continue _function;
}
}
return factorialTailCall(n, 1);
}
颿°factorialTailCallãwhileã䜿ã£ãã«ãŒãã«å€æãããŠããã®ãåãããŸããïŒ
ãŸãšã
ååž°é¢æ°ãå©çšãããšã«ãŒãããããšã¬ã¬ã³ãã«ã³ãŒããæžããå Žåãããã®ã§ãããããã®JavaScript(ES6)ã§ã¯ç©æ¥µçã«äœ¿ã£ãŠãããããšããã§ãããã ããéåžžã®ååž°ã§ã¯ãªããæ«å°Ÿååž°ã§ãªããã°å®è¡æã®å¹çãæªããšãã課é¡ããããŸããæ¹éãšããŠã¯ããŸãã¯éåžžã®ååž°é¢æ°ã§ã³ãŒãåããåŸãååž°é¢æ°ãæ«å°Ÿååž°ã«ãªãã¡ã¯ã¿ãªã³ã°ãããšããæµãã«ãªãã§ããããååž°é¢æ°ã®äœæã®ç§èš£ã¯ãããã°ã©ãã³ã°Haskellã«ç޹ä»ãããŠããŸãã®ã§æ¯éåç §ããŠã¿ãŠãã ããã
ä»é²
å€éååž°
èªåèªèº«ãè€æ°ååŒã³åºãååž°é¢æ°ã å€éååž°é¢æ° ãšåŒã³ãŸãããã£ããããæ°ãæ±ãã以äžã®é¢æ°ã¯å€éååž°é¢æ°ã§ãã
// ãã£ããããæ°ãæ±ãã颿°
function fibonacci(n) {
if (n === 0 || n === 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
console.log(fibonacci(0)); // 0
console.log(fibonacci(1)); // 1
console.log(fibonacci(2)); // 1
console.log(fibonacci(3)); // 2
console.log(fibonacci(4)); // 3
çžäºååž°
è€æ°ã®é¢æ°ãããããããåŒã³åºãåãå Žåããããã®é¢æ°ã çžäºååž°é¢æ° ãšåŒã³ãŸããäŸãã°ã以äžã®å¶æ°ã»å¥æ°ãå€å®ãã颿°ã¯çžäºååž°é¢æ°ã§ãã
// nãå¶æ°ãªãã°trueãè¿ã颿°
function isEven(n) {
if (n === 0) {
return true;
}
return isOdd(n - 1);
}
// nã奿°ãªãã°trueãè¿ã颿°
function isOdd(n) {
if (n === 0) {
return false;
}
return isEven(n - 1);
}
ES6ã®æ«å°ŸåŒã³åºãæé©åã®ä»æ§
ES6ã§ã¯æœè±¡æäœé¢æ°ã®PrepareForTailCallã®å®è¡æã®æå³è«ãšããŠãæ«å°ŸåŒã³åºãæã®ã³ãŒã«ã¹ã¿ãã¯ã®åäœãå®çŸ©ãããŠããããã§ããPrepareForTailCallã¯æ«å°ŸåŒã³åºãã®äœçœ®ã«ãã颿°ãåŒã³åºãåã«çŸåšã®ã³ãŒã«ã¹ã¿ãã¯ã®å é ã®ã¹ã¿ãã¯ãã¬ãŒã ïŒã€ãŸãåŒã³åºãå 颿°ã®ã¹ã¿ãã¯ãã¬ãŒã ïŒãpopããŸããæ¬¡ã«ã颿°åŒã³åºããçºçãããšæ°ããã¹ã¿ãã¯ãã¬ãŒã ãpushããŸããæ¬èšäºã§ã¯ã¹ã¿ãã¯ãã¬ãŒã ãåå©çšãããšããåæã§è§£èª¬ããŸããããES6ã§ã¯ããã£ããpopããŠããå床pushããŠããããã§ããã
ãŸããã¹ã¿ãã¯ãã¬ãŒã ãpopãããšé¢æ°ã®æ»ãå ã¯æ¶ããã ãããšæããŸããããES6ã®ã¹ã¿ãã¯ãã¬ãŒã ã¯æ»ãå ã®äœçœ®ã§ã¯ãªããçŸåšå®è¡äžã®äœçœ®ãä¿æããŠããããã§ããã€ãŸãã颿°åŒã³åºãæã«çŸåšã®äœçœ®ãä¿æããŠããæ°ããã¹ã¿ãã¯ãã¬ãŒã ãpushããŸãã颿°ã®åŒã³åºããçµäºãããšã¹ã¿ãã¯ãã¬ãŒã ãpopããèšæ¶ããŠããäœçœ®ããå®è¡ãåéããããã§ãããã®èŸºã¯å®å šã«çè§£ããŠããããã§ã¯ãªãã®ã§ééã£ãŠããå¯èœæ§ããããŸããã容赊ãã ããã
PrepareForTailCallã®æå³è«ã®NOTEãšããŠã以äžã®ããã«èšè¿°ãããŠããŸãã
For example, a tail position call should only grow an implementationâs activation record stack by the amount that the size of the target functionâs activation record exceeds the size of the calling functionâs activation record. If the target functionâs activation record is smaller, then the total size of the stack should decrease.
ã€ãŸããåŒã³åºãå 颿°ã®ã¹ã¿ãã¯ãã¬ãŒã ïŒåæã§ã¯ã¢ã¯ãã£ããŒã·ã§ã³ã¬ã³ãŒããšãããŸãïŒã®ãµã€ãºãåŒã³åºãå 颿°ã®ã¹ã¿ãã¯ãã¬ãŒã ã®ãµã€ãºããè¶ éããåã ããã³ãŒã«ã¹ã¿ãã¯ã®ç·ãµã€ãºã¯å€§ãããªãïŒãããã¯å°ãããªãïŒãšããããšã§ããã