Skip to content

Instantly share code, notes, and snippets.

@IronSavior
Last active May 5, 2016 06:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IronSavior/8e6e787f7b388eaa50d6aa8439e43fe4 to your computer and use it in GitHub Desktop.
Save IronSavior/8e6e787f7b388eaa50d6aa8439e43fe4 to your computer and use it in GitHub Desktop.
Obligatory Y combinator exercise
# 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