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!

相關文章
相關標籤/搜索