[JS]|[JS] generator版的阴阳谜题
1. 背景
阴阳谜题(yin yang puzzle),指的是以下Scheme代码实现的无限循环,
(let* [(yin ((lambda (foo) (newline) foo)
(call/cc (lambda (bar) bar))))
(yang ((lambda (foo) (display "*") foo)
(call/cc (lambda (bar) bar))))]
(yin yang))
输出结果为,
*
**
***
****
*****
******
*******
...
2. Python实现的阴阳谜题
今天在知乎看到了,
阴阳谜题的Python实现,就顺势把它翻译成了JS版。
def puzzle():
def yin(yin):
yield '@'
def yang(yang):
yield '*'
yield from yin(yang)
yield from yang(yang)
yield from yin(yin)for x, _ in zip(puzzle(), range(256)):
print(x, end='')
print()
3. JavaScript
function* solution() {
function* yin(_yin) {
yield '@';
function* yang(_yang) {
yield '*';
yield* _yin(_yang);
}yield* yang(yang);
}yield* yin(yin);
}const iter = solution();
console.log(iter.next());
// @
console.log(iter.next());
// *
console.log(iter.next());
// @
console.log(iter.next());
// *
console.log(iter.next());
// *
console.log(iter.next());
// @
console.log(iter.next());
// *
console.log(iter.next());
// *
console.log(iter.next());
// *
console.log(iter.next());
// @
4. 原理分析
function* solution() {
function* yin(_yin) {
// 2. yin=yin1, _yin=yin1
// 8. yin=yin1, _yin=yang1
// 17. yin=yin1, _yin=yang2
// 29. yin=yin1, _yin=yang3
// 44. yin=yin1, _yin=yang4yield '@';
// 3. total output: @
// 9. total output: @*@
// 18. total output: @*@**@
// 30. total output: @*@**@***@
// 45. total output: @*@**@***@****@function* yang(_yang) {
// 5. yang=yang1, _yang=yang1, (_yin=yin1)// 11. yang=yang2, _yang=yang2, (_yin=yang1)
// 14. yang=yang1, _yang=yang2, (_yin=yin1)// 20. yang=yang3, _yang=yang3, (_yin=yang2)
// 23. yang=yang2, _yang=yang3, (_yin=yang1)
// 26. yang=yang1, _yang=yang3, (_yin=yin1)// 32. yang=yang4, _yang=yang4, (_yin=yang3)
// 35. yang=yang3, _yang=yang4, (_yin=yang2)
// 38. yang=yang2, _yang=yang4, (_yin=yang1)
// 41. yang=yang1, _yang=yang4, (_yin=yin1)// 47. yang=yang5, _yang=yang5, (_yin=yang4)
// 50. yang=yang4, _yang=yang5, (_yin=yang3)
// 53. yang=yang3, _yang=yang5, (_yin=yang2)yield '*';
// 6. total output: @*
// 12. total output: @*@*
// 15. total output: @*@**
// 21. total output: @*@**@*
// 24. total output: @*@**@**
// 27. total output: @*@**@***
// 33. total output: @*@**@***@*
// 36. total output: @*@**@***@**
// 39. total output: @*@**@***@***
// 42. total output: @*@**@***@****
// 48. total output: @*@**@***@****@*
// 51. total output: @*@**@***@****@**
// 54. total output: @*@**@***@****@***yield* _yin(_yang);
// 7. _yin=yin1, _yang=yang1
// 13. _yin=yang1, _yang=yang2
// 16. _yin=yin1, _yang=yang2
// 22. _yin=yang2, _yang=yang3
// 25. _yin=yang1, _yang=yang3
// 28. _yin=yin1, _yang=yang3
// 34. _yin=yang3, _yang=yang4
// 37. _yin=yang2, _yang=yang4
// 40. _yin=yang1, _yang=yang4
// 43. _yin=yin1, _yang=yang4
// 49. _yin=yang4, _yang=yang5
// 52. _yin=yang3, _yang=yang5
// 55. _yin=yang2, _yang=yang5
}yield* yang(yang);
// 4. yang=yang1
// 10. yang=yang2
// 19. yang=yang3
// 31. yang=yang4
// 46. yang=yang5
}yield* yin(yin);
// 1. yin=yin1
}
以上代码中,我用序号标明了前
55
步的执行过程。注:
(1)每次执行到
function* yang(){}
会创建一个新的generator。以上用
yang1
,yang2
,yang3
,yang4
,yang5
,来标记所创建的不同generator。【[JS]|[JS] generator版的阴阳谜题】(2)由于JS遵循词法作用域规则(闭包),
使用
yield*
调用一个generator,进入函数上下文后,函数内部自由变量的绑定,是该generator被创建时,词法环境中的值。
例如,第
4
步yield* yang(yang);
,此时yang=yang1
,于是第
5
步,yang=yang1, _yang=yang1
,表示调用了
yang1
函数,参数_yang
绑定为yang1
。这时词法环境中
_yin=yin1
,所以,我们把它放到了后面的小括号中,写为,5. yang=yang1, _yang=yang1, (_yin=yin1)
。等到第
13
步yield* yang(yang);
,此时_yin=yang1, _yang=yang2
,于是第
14
步,yang=yang1, _yang=yang2
,表示再次调用了
yang1
函数,参数_yang
绑定为yang2
。这时词法环境中
_yin
的值,还是yang1
创建时的_yin
值,我们找到了第
5
步的记录,5. yang=yang1, _yang=yang1, (_yin=yin1)
,得知,
_yin=yin1
,因此,
14. yang=yang1, _yang=yang2, (_yin=yin1)
。(3)由于
yang
函数内部,_yin
的词法绑定总是会发生变化,因此,
yang
函数实际上相当于在进行循环执行。例如,// 32. yang=yang4, _yang=yang4, (_yin=yang3)
// 35. yang=yang3, _yang=yang4, (_yin=yang2)
// 38. yang=yang2, _yang=yang4, (_yin=yang1)
// 41. yang=yang1, _yang=yang4, (_yin=yin1)
以上代码,相当于利用词法绑定,实现了循环操作。
参考
Python 实现阴阳谜题(Yin Yang Puzzle)
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量