call

[...]

(...)

def y(&f)

lambda { |*args| f[y(&f)][*args] }

end



y(&f)

yf

yf

def y(&f)

lambda { |yf|

lambda { |*args| f[yf[yf]][*args] }

}[ <<< placeholder for yf: we'll fill this hole next >>> ]

end



yf

y(&f)

y

def y(&f)

lambda { |yf|

lambda { |*args| f[yf[yf]][*args] }

}[ lambda { |yf| lambda { |*args| f[yf[yf]][*args] } } ]

end



fac = y { |rec| lambda { |n| n < 2 ? 1 : n * rec[n-1] } }

fac[5] # ==> 120



lambda { |yf| lambda { |*args| f[yf[yf]][*args] } }



x

x[x]

x

x

def y(&f)

lambda { |x| x[x] } [

lambda { |yf| lambda { |*args| f[yf[yf]][*args] } } ]

end



acc_fac = y { |rec| lambda { |n,acc| n < 2 ? acc : rec[n-1, n*acc] } }

tail_fac = lambda { |n| acc_fac[n, 1] }

tail_fac[5] # ==> 120



In a comment on But Y would I want to do a thing like this? Tom Moertel derived an elegant version of the actual Y combinator in Ruby. I reproduce his words here with permission.Tom uses the alternate syntax for. I avoided this to keep clear of a tiresome debate about operator overloading. (On one side: those who hate it. On the other side: those that hate Ruby disallowing overloading).Ok Tom, take it away!Here’s my original Ruby definition:To get rid of the recursive call, let’s replace it with a variable, whose value we’ll say is magically equivalent to the result of the recursive call. To effect the binding of, we’ll need to wrap the method body in a new lambda expression and pass in the magic value:So, what value should we pass in for? Because the variable represents the value that would have been computed by calling, which is just the body of themethod, we can fill the hole with a duplicate of the body:And we have our Y combinator:While the combinator works, its implementation repeats itself: there are two copies of the lambda expressionin the method body. To factor them out, let’s let the variablerepresent this expression. Then the method body simplifies to, which is very satisfying. To setto the correct value, however, we need to add a wrapper lambda that bindsto the original expression. Putting it all together, we arrive at the final version:And it, too, works:Cheers! — Tom

Labels: lispy, ruby