我建立了一個Y型組合子在JS這樣Y型結合器在JavaScript
const y = f => { const g = self => x => f(self(self))(x); return g(g);}
,我簡化了這樣
const y = f => { const g = self => f(self(self)); return g(g);}
此得到無限遞歸的代碼。 這兩個版本有什麼區別?
我建立了一個Y型組合子在JS這樣Y型結合器在JavaScript
const y = f => { const g = self => x => f(self(self))(x); return g(g);}
,我簡化了這樣
const y = f => { const g = self => f(self(self)); return g(g);}
此得到無限遞歸的代碼。 這兩個版本有什麼區別?
如果你不明白兩者之間的差別,我會驚訝你實際上建立了它們。然而,也許是爲了證明兩者之間的區別的最好辦法,是按照他們的評價
const y = f => {
const g = self => x => f(self(self))(x)
return g(g)
}
y (z) ...
// (self => x => z(self(self))(x)) (self => x => z(self(self))(x)) ...
// returns:
// x => z((self => x1 => z(self(self))(x1))(self => x2 => z(self(self))(x2)))(x)
好了,y(z)
(其中z
一些功能,這並不重要)返回函數x => ...
。直到申請那個功能,評價在那裏停止。
現在讓我們來比較,爲您的第二個定義
const y = f => {
const g = self => f(self(self))
return g(g)
}
y (z) ...
// (self => z(self(self))) (self => z(self(self)))
// z((self => z(self(self)))(self => z(self(self)))) ...
// z(z((self => z(self(self)))(self => z(self(self))))) ...
// z(z(z((self => z(self(self)))(self => z(self(self)))))) ...
// z(z(z(z((self => z(self(self)))(self => z(self(self))))))) ...
// ... and on and on
所以y (z)
永遠不會終止 - 在JavaScript中,它使用應用性爲了評估至少 - 在功能參數進行評估之前被調用的功能應用
替代Y-組合器
在這裏,我們可以從組最多
// standard definition
const Y = f => f (Y (f))
// prevent immediate infinite recursion in applicative order language (JS)
const Y = f => f (x => Y (f) (x))
// remove reference to self using U combinator
const U = f => f (f)
const Y = U (h => f => f (x =>h (h) (f) (x)))
建立一個Y型組合子讓我們來測試一下
const U = f => f (f)
const Y = U (h => f => f (x => h (h) (f) (x)))
// range :: Int -> Int -> [Int]
const range = Y (f => acc => x => y =>
x > y ? acc : f ([...acc,x]) (x + 1) (y)) ([])
// fibonacci :: Int -> Int
const fibonacci = Y (f => a => b => x =>
x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1)
console.log(range(0)(10).map(fibonacci))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ]
還是我最近喜歡
// simplified Y
const Y = f => x => f (Y (f)) (x)
// range :: Int -> Int -> [Int]
const range = Y (f => acc => x => y =>
x > y ? acc : f ([...acc,x]) (x + 1) (y)) ([])
// fibonacci :: Int -> Int
const fibonacci = Y (f => a => b => x =>
x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1)
console.log(range(0)(10).map(fibonacci))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ]
我引用了這個答案[這裏](https://stackoverflow.com/questions/48714823/finite-number-of-recursions-in-javascript-with-es6-y-combinator/48715151?noredirect=1#comment84430385_48715151)。 .. –
感謝分享我的工作,喬納斯^ _ ^ – naomik
第一個是懶惰的。由於Javascript是嚴格評估的,你需要冗餘'x => f ...(x)'(而不是'f ...')來防止無限遞歸。 – ftor
第一個實際上是z組合子。又稱爲渴望語言。 – Sylwester