34 lines
615 B
Ruby
34 lines
615 B
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
module MutualRecursion
|
||
|
UNEXPECTED_TYPE = 'expected tail_call or terminal_value'
|
||
|
|
||
|
class TailCall
|
||
|
attr_reader :value, :block
|
||
|
|
||
|
def initialize(value = nil, &block)
|
||
|
@value = value
|
||
|
@block = block
|
||
|
end
|
||
|
|
||
|
def invoke
|
||
|
self.then do |tail|
|
||
|
while tail.block
|
||
|
tail = tail.block.call
|
||
|
raise TypeError, UNEXPECTED_TYPE unless tail.is_a?(TailCall)
|
||
|
end
|
||
|
|
||
|
tail.value
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def tail_call
|
||
|
MutualRecursion::TailCall.new { yield }
|
||
|
end
|
||
|
|
||
|
def terminal_value(value)
|
||
|
MutualRecursion::TailCall.new(value)
|
||
|
end
|