diff --git a/README.md b/README.md index e69de29..22b1450 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,46 @@ +# Mutual Recursion + +Tail call optimization for mutually (and directly) recursive functions in Ruby. + +The current desing uses a trampoline. However, it is implemented in a way that still allows a tail recursive function to return a Proc as its terminal value without it being called prematurely by accident. +### examples +```ruby +require 'mutual_recursion' + +def mutual_one(x, y = 0) + return terminal_value(y) if x.negative? + + tail_call { mutual_two(x, y + 1) } +end + +def mutual_two(x, y) + tail_call { mutual_one(x - 1, y) } +end + +mutual_one(50_000).invoke +# => 50001 +``` +```ruby +require 'mutual_recursion' + +def direct(x, y = 0) + return terminal_value(y) if x.negative? + + tail_call { direct(x - 1, y + 1) } +end + +direct(50_000).invoke +# => 50001 +``` +```ruby +require 'mutual_recursion' + +def proc_returning(x, y = 0) + return terminal_value(proc { "|#{y}|" }) if x.negative? + + tail_call { proc_returning(x - 1, y + 1) } +end + +proc_returning(20).invoke.call +# => "|21|" +``` diff --git a/mutual_recursion.gemspec b/mutual_recursion.gemspec index 0ec7766..a4de4d5 100644 --- a/mutual_recursion.gemspec +++ b/mutual_recursion.gemspec @@ -8,6 +8,6 @@ Gem::Specification.new do |s| s.description = 'Tail call optimization for mutually (and directly) recursive functions using a trampoline.' s.authors = ['Mike'] s.files = ['lib/mutual_recursion.rb'] - s.homepage = '' + s.homepage = 'https://gitlab.com/mike-cifelli/mutual_recursion' s.license = 'MIT' end diff --git a/test/mutual_recursion_test.rb b/test/mutual_recursion_test.rb index 0b7e5af..4f5fa80 100644 --- a/test/mutual_recursion_test.rb +++ b/test/mutual_recursion_test.rb @@ -37,7 +37,7 @@ class InventoryTest < Minitest::Test end def test_recursive_function_can_return_proc - tail = proc_returning + tail = proc_returning(20) assert_kind_of(Proc, tail.invoke) end @@ -76,8 +76,10 @@ def lambda_returning terminal_value(-> { 24 }) end -def proc_returning - terminal_value(proc { 24 }) +def proc_returning(x, y = 0) + return terminal_value(proc { puts "|#{y}|" }) if x.negative? + + tail_call { proc_returning(x - 1, y + 1) } end def bad_return