Last active
May 5, 2016 06:54
-
-
Save IronSavior/8e6e787f7b388eaa50d6aa8439e43fe4 to your computer and use it in GitHub Desktop.
Obligatory Y combinator exercise
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Fixed point combinator. Because reasons. | |
# @param [Block with arity 1] Receives recursion Proc, must return Proc representing function (any arity) | |
# @return [Proc] | |
def Y | |
fail unless block_given? | |
lambda{ |fn| fn.call fn }.call lambda{ |fn| | |
lambda{ |*args| | |
(yield fn.call fn).call *args | |
} | |
} | |
end | |
# Demonstration | |
demo1 = Y do |recurse| | |
lambda{ |x| | |
x < 1 ? 0 : x + recurse[x - 1] | |
} | |
end # => Proc | |
demo1[3] # => 6 | |
# The Y method above requires the user to explicitly return a proc of arity 1 in order to | |
# satisfy its interface. While that is fairly mundane for functional languages, it seems | |
# somewhat out of place in a ruby program. This is a convenience method that wraps arbitrary | |
# code blocks in the necessary boilerplate and thus presents a more idiomatic interface for | |
# the user. The recursion callback is passed to the block as the last parameter. | |
# @param [Block of arity > 1] The last parameter is the recursion callback | |
# @return [Proc with same arity as given block] The given code block wired up for recursion. | |
def recursive | |
fail unless block_given? | |
Y{ |recurse| | |
lambda{ |*args| yield *args, recurse } | |
} | |
end | |
# Demonstration | |
demo2 = recursive do |x, recurse| | |
x < 1 ? 0 : x + recurse[x - 1] | |
end # => Proc | |
demo2[3] # => 6 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment