简体   繁体   English

javascript中的y-combinator

[英]y-combinator in javascript

I have built a y-combinator in js like this 我已经在js中建立了一个y-combinator

const y = f => { const g = self => x => f(self(self))(x); return g(g);}

and I simplified this code like this 我这样简化了这段代码

 const y = f => { const g = self => f(self(self)); return g(g);}

this get an infinite recursion. 这得到了无限递归。 What's the difference between these two versions? 这两个版本有什么区别?

If you don't understand the difference between the two, I would be surprised that you actually built them. 如果您不了解两者之间的区别,那么您实际上构建了它们,我会感到惊讶。 Nevertheless, perhaps the best way to demonstrate the difference between the two, is to follow their evaluation 然而,证明两者之间差异的最好方法是遵循他们的评估。

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)

Ok, so y(z) (where z is some function, it doesn't matter) returns a function x => ... . 好的,所以y(z) (其中z是某个函数,没关系)返回一个函数x => ... Until we apply that function, evaluation stops there. 在我们应用功能之前,评估到此为止。

Now let's compare that to your second definition 现在,将其与您的第二个定义进行比较

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

So y (z) never terminates – at least in JavaScript which uses applicative order evaluation – where function arguments are evaluated before the called function is applied 因此y (z)永远不会终止-至少在使用应用顺序评估的JavaScript中-在应用调用函数之前先评估函数参数


Alternate Y-combinators 备用Y组合器

Here we can build a Y-combinator from the ground up 在这里,我们可以从头开始构建一个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)))

Let's test it out 让我们测试一下

 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 ] 

Or my recent favourite 或我最近的最爱

 // 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 ] 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM