1

我試圖在Javascript中實現Y組合器。在Javascript中,爲什麼我不能用f(f)代替x => f(f)(x)?

我設法執行下列規定:

const y0 = gen => (f => f(f))(f => gen(x => f(f)(x))); 
const factorial0 = y0(fact => n => n<=2 ? n : n * fact(n-1)); 
console.log(factorial0(5)); 
// 120 

它運作良好。

然後我正在考慮表達式x => f(f)(x)

我的理解是,表達式x => g(x)等於g。將y應用於x => g(x)評估爲g(y),同時將y應用於g也評估爲g(y)

所以我用f(f)替換了x => f(f)(x)

const y = gen => (f => f(f))(f => gen(f(f))); 
const factorial = y(fact => n => n<=2 ? n : n * fact(n-1)); 
console.log(factorial(5)); 
// RangeError: Maximum call stack size exceeded 

但是這個版本崩潰了堆棧溢出。

那麼x => f(f)(x)f(f)之間的區別是什麼,這樣一個工程和其他崩潰。

+1

因爲嚴格評估。 – Bergi

+1

@Bergi三個字 - 我把它稱爲一個懶惰的解釋:D – ftor

回答

2

我認爲正在發生的是那兩個表達式不完全相同。

一方面x => f(f)(x) - 這將創建一個新的函數文本(所以它不會被調用的時候了 - 它被調用,只有當這個函數被調用)

在另一方面f(f) - 這在Javascript中是一個表達式調用f函數。所以你的情況會導致堆棧溢出。

+1

或換句話說,'x => f(f)(x)'是f(f)'的懶惰版本。由於Javascript是嚴格評估的,我們必須將'f(f)'這樣的模式包裝到lambda中以避免無限遞歸。 – ftor

+0

我認爲這是問題的關鍵。表達式x => f(f)(x)延遲f(f)的評估直到提供x。 –

4

x => f(f)(x) 

是採取一個參數,x功能。當函數被調用時,它又調用函數f,將參考傳遞給f作爲參數。函數f返回另一個函數,然後調用該函數,並將x作爲參數傳遞。

在老派的語法,這是

function(x) { 
    return f(f)(x); 
} 

這不僅僅是f(f)本身顯著不同。這只是函數「f」的調用,而「f」作爲參數傳遞。

因此x => f(f)(x)f(f)都是表達式,但它們表示明顯不同的語義。第一個值是對函數的引用;表達式本身不做其他任何事情 —特別是,不調用函數f()f(f)的值是什麼函數f()當被調用時返回—表達式確實是做些什麼,那是什麼函數f()

相關問題