# 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