How to Make Fibonacci Confusing

前几天同事发了这么一段代码javascript

(fn =>
    (f => f(f))(f => fn(n => f(f)(n)))
)(g =>
    n => [1, 2].indexOf(n) > -1 ? 1 : g(n - 1) + g(n - 2)
)(10);

猜你看这段代码时,必定是这样的心情:java

What the fuck


好端端的斐波那契是怎么变成这样的,因吹斯听,咱们来回放一下。app

从正常的写法开始:函数

const fib = n => [1, 2].indexOf(n) >= 0 ? 1 : fib(n - 1) + fib(n - 2);

为了让上面看起来不像递归,改写一下。
把递归调用改为调用参数gcode

const wrappedFib = g => n => [1, 2].indexOf(n) >= 0 ? 1 : g(n - 1) + g(n - 2);

无论g传什么,例如就传null,1,2两项我均可以计算了,由于压根和g无关。blog

wrappedFib(null)(1);
wrappedFib(null)(2);

若是要计算第3项,那个人g就能够是wrappedFib(null)递归

let g = wrappedFib(null);
wrappedFib(g)(3);

同理,第4项ip

let g = wrappedFib(wrappedFib(null));
wrappedFib(g)(4);

第5项......第N项我就不列了it

看起来须要构造一个g,他由无限层的wrappedFib组成。console

递归的思想

const g = n => wrappedFib(g)(n);

运行一下试试吧

const wrappedFib = g => n => [1, 2].indexOf(n) >= 0 ? 1 : g(n - 1) + g(n - 2);
const g = n => wrappedFib(g)(n);
console.log(wrappedFib(g)(10));

题外话
g自己就是由无限层wrappedFib组成的
因此wrappedFib(g)g是等价的
所以,也能够直接调console.log(g(10));

const g = n => wrappedFib(g)(n);

又看到了明显的递归对不对,试着把它藏起来,思想跟开始的wrappedFib函数同样,经过参数传进来,这段要花点时间理解。

const g = (f => n => wrappedFib(f(f))(n))(f => n => wrappedFib(f(f))(n));

方法自己和方法传参是同样的,换个写法

const g = (f => f(f))(f => n => wrappedFib(f(f))(n));

能到这里,咱们和最终的代码已经很接近了,把g中的wrappedFib去掉,经过参数fn传进来。

const gWaitForWrappedFib = fn => (f => f(f))(f => n => fn(f(f))(n));
const g = gWaitForWrappedFib(wrappedFib);

好了,去掉const常量的定义,所有连起来吧

(fn =>
    (f => f(f))(f => fn(n => f(f)(n)))
)(g =>
    n => [1, 2].indexOf(n) > -1 ? 1 : g(n - 1) + g(n - 2)
)(10);

拆解这段代码挺烧脑,膜拜一下代码的做者。
虽然想不出有什么用,可是颇有趣,有趣就值得研究:D

Code For Fun!

相关文章
相关标签/搜索