2009-11-23 21 views

Trả lời

4

Tùy thuộc vào các chi tiết của mã thực tế của bạn, nhưng ví dụ của bạn, nếu bạn đặt tên cho khối trước, bạn có thể tránh tạo ra giá trị và khối trong hàm của bạn. Ví dụ:

def f(x, &b) 
    yield x 
end 

foo = lambda do |i| 
    p i 
    f(i-1,&foo) if i > 0 
end 
f(4,&foo) 

Tuy nhiên, tôi muốn tìm giải pháp thanh lịch hơn cho vấn đề này. Tôi nghi ngờ đây sẽ là một ứng dụng tốt của bộ kết hợp Y. Ngay sau khi tôi có một cái gì đó tốt hơn cho bạn, tôi sẽ cập nhật thông báo này.

+0

Điều đó tốt, mặc dù tôi nghi ngờ về lambda cho trường hợp của tôi vì nó có cùng số lượng byte như def f..end. Điều này đã trở thành một chút thú vị trừu tượng nhưng tất cả bắt đầu với điều này: http://stackoverflow.com/questions/1766675/code-golf-running-water/1770264#1770264 – DigitalRoss

+0

Vâng, thật không may, nếu đó là số lượng ký tự ít nhất được sử dụng bạn đang sử dụng, việc sử dụng lambda có lẽ sẽ không hữu ích lắm. Ngay cả cú pháp viết tắt -> được tìm thấy trong Ruby 1.9 vẫn có thể sẽ không tiết kiệm được nhiều, một khi bạn bao gồm mã y-combinator. Nếu bạn không quen với nó, hoặc nếu bất kỳ người đọc khác là, ví dụ trong Ruby có thể được tìm thấy ở đây: http://nex-3.com/posts/43-fun-with-the-y-combinator-in-ruby và ở đây: http://www.eecs.harvard.edu/~cduan/technical/ruby/ycombinator.shtml –

+0

Tuy nhiên, một vấn đề rất thú vị. Tôi sẽ nhai nó nhiều hơn một chút trước khi chấp nhận rằng lambda được đặt tên là con đường ngắn nhất để đi. –

1
def f(x, &b) 
    b.call x 
    f(x-1,&b) if x>0 
end 

f(4) do |x| 
p x 
end 
2

Một khối có thể tự gọi một cách đệ quy miễn là nó được lưu trữ trong một biến có thể truy cập bởi chính khối đó. Ví dụ:

def f(x) 
    block = lambda do |y| 
    # some calculation on value, or simply yield to the block passed to f() 
    yield y 
    block.call(y - 1) if y > 0 
    end 
    block.call(x) 
end 

f(4) do |x| 
    puts "Yielded block: #{x}" 
end 

Hoặc, bạn có thể trả lại khối đệ quy, được liên kết với khối người gọi và sau đó gọi khối đó. Ví dụ:

def g 
    block = lambda do |y| 
    # some calculation on value, or simply yield to block passed to g() 
    yield y 
    block.call(y - 1) if y > 0 
    end 
end 

printing_descender = g do |x| 
    puts "Encapsulated block: #{x}" 
end 
printing_descender.call(4) 

Đầu ra:

Yielded block: 4 
Yielded block: 3 
Yielded block: 2 
Yielded block: 1 
Yielded block: 0 
Encapsulated block: 4 
Encapsulated block: 3 
Encapsulated block: 2 
Encapsulated block: 1 
Encapsulated block: 0 
0

câu trả lời của Matt là tốt. Nó cũng là cách duy nhất để thực hiện một sự trở lại ngay lập tức từ một tìm kiếm đệ quy sâu sắc. Lưu ý rằng việc trả về từ khối thực sự trở về từ hàm gọi. tháo tất cả các cuộc gọi khối đệ quy trong một lần rơi.

+0

Điều này thực sự phụ thuộc nếu bạn sử dụng 'lambda' hoặc' proc'. lambda là các hàm ẩn danh có thể được trả về, thực thi của proc trong phạm vi hàm cha và trả về sẽ làm như bạn nói. –

0

có rất nhiều cách để thực hiện việc này bằng cách sử dụng callcc hoặc catch/throw (luôn có thể quay lại từ các cuộc gọi đệ quy sâu). đây là phiên bản không chơi gôn sử dụng các chuỗi địa phương theo chủ đề

def f x, &b 
    t = Thread.current 
    t[:b] ||= b 
    b ||= t[:b] 
    b.call(x) 
ensure 
    t[:b] = nil 
end 

f 4 do |i| 
    p i 
    f i - 1 if i > 0 
end 
Các vấn đề liên quan