2016-02-19 7 views
-1

Как рекурсия Ruby может быть «саботирована», чтобы отключить способность рубиновых методов участвовать в рекурсии?Отключить рекурсию в Ruby для принудительного использования Y Combinator

Необходим для создания программы обучения лямбда-исчислению, но с использованием Ruby.

Мотивация от Crockford на JavaScript - https://www.youtube.com/watch?v=ya4UHuXNygM&feature=youtu.be&t=1h9m53s

+0

Что вы пытаетесь достичь? –

+0

Можете ли вы уточнить? – sawa

+1

Даже если бы оно существовало, это приложение нарушило бы почти 102% функциональности рубинового ядра. – mudasobwa

ответ

2

Вы можете использовать TracePoint API для отслеживания всех вызовов и возвращает метод и построить стек, чтобы увидеть ли метод, который вызывается уже в стеке. Таким образом, вы можете по крайней мере обнаружить рекурсии, а затем вы можете просто raise исключение или exit программы.

Что-то вроде:

stack = [] 

TracePoint.trace(:call, :return) do |trace| 
    p trace, stack 
    method = trace.method_id 
    case trace.event 
    when :call 
    if stack.include?(method) 
     $stderr.puts "RECURSION DETECTED: method `#{stack.last}` calls method `#{method}`." 
     exit! 
    end 
    stack.push(method) 
    when :return 
    stack.pop 
    end 
end 

def foo; bar end 
def bar; baz end 
def baz; qux end 
def qux; bar end 

foo 

Обратите внимание, что я застрял в отладочный p RINT там, так что вы можете наблюдать, как он работает:

#<TracePoint:call `foo'@./test.rb:20> 
[] 
#<TracePoint:call `bar'@./test.rb:21> 
[:foo] 
#<TracePoint:call `baz'@./test.rb:22> 
[:foo, :bar] 
#<TracePoint:call `qux'@./test.rb:23> 
[:foo, :bar, :baz] 
#<TracePoint:call `bar'@./test.rb:21> 
[:foo, :bar, :baz, :qux] 
RECURSION DETECTED: method `qux` calls method `bar`.