Sự khác biệt giữa đệ quy đuôi và đệ quy cấu trúc


8

Có sự khác biệt nào giữa đệ quy cấu trúc và đệ quy đuôi hay cả hai đều giống nhau không? Tôi thấy rằng trong cả hai lần truy xuất này, hàm đệ quy được gọi trên tập hợp con của các mục gốc.


7
Bạn đã làm nghiên cứu gì? Sự hiểu biết của bạn về đệ quy đuôi là gì? Tại sao bạn nghĩ rằng nó tương tự như đệ quy cấu trúc?
Jonathan Cast

Bất kỳ cơ hội nào bạn có thể thêm những gì bạn thấy khiến bạn nghĩ rằng chúng có thể giống hoặc rất giống nhau? Nó có thể giúp người hướng dẫn làm rõ nó khi dạy các khái niệm cho mọi người.
dùng541686

Câu trả lời:


28
  1. Đệ quy cấu trúc: các cuộc gọi đệ quy được thực hiện trên các đối số có cấu trúc nhỏ hơn .

  2. Đệ quy đuôi: cuộc gọi đệ quy là điều cuối cùng xảy ra.

Không có yêu cầu rằng đệ quy đuôi nên được gọi trên một đối số nhỏ hơn. Trong thực tế, khá thường xuyên các hàm đệ quy được thiết kế để lặp lại mãi mãi. Ví dụ: đây là một đệ quy đuôi tầm thường (không hữu ích lắm, nhưng đó là đệ quy đuôi):

def f(x):
   return f(x+1)

Chúng tôi thực sự phải cẩn thận hơn một chút. Có thể có một số lệnh gọi đệ quy trong một hàm và không phải tất cả chúng đều cần được đệ quy đuôi:

def g(x):
  if x < 0:
    return 42             # no recursive call
  elif x < 20:
     return 2 + g(x - 2)  # not tail recursive (must add 2 after the call)
  else:
     return g(x - 3)     # tail recursive

Một người nói về các cuộc gọi đệ quy đuôi . Một chức năng mà các cuộc gọi đệ quy được tất cả các đuôi-đệ quy sau đó được gọi là một hàm đuôi-đệ quy.



Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
DW

-1

Đệ quy đuôi là một trường hợp rất đơn giản của đệ quy cấu trúc, trong đó cấu trúc được đề cập là một danh sách liên kết . Trong ngôn ngữ mà bạn có thể đang sử dụng chủ yếu, danh sách này có thể không có nghĩa đen trong mã; đúng hơn, đó là một "danh sách các cuộc gọi đến hàm" theo khái niệm, một khái niệm có thể không thể diễn đạt bằng văn bản sử dụng ngôn ngữ đó. Trong Haskell (ngôn ngữ của tôi), bất kỳ lệnh gọi hàm đệ quy nào thực sự có thể được thay thế bằng các hành động tuần tự trên một danh sách theo nghĩa đen có các phần tử theo nghĩa đen là "gọi hàm", nhưng đây có lẽ là một ngôn ngữ chức năng.

Đệ quy cấu trúc là một cách vận hành trên một đối tượng được định nghĩa là một hỗn hợp của các đối tượng khác (có thể là hỗn hợp). Ví dụ, cây nhị phân là một đối tượng chứa các tham chiếu đến hai cây nhị phân hoặc trống (do đó, nó là một đối tượng được định nghĩa đệ quy ). Ít tự tham chiếu hơn, một cặp (t1, t2) chứa hai giá trị của một số loại t1 và t2 thừa nhận đệ quy cấu trúc, mặc dù t1 và t2 không cần phải là cặp. Đệ quy này có dạng

hành động trên cặp = kết hợp kết quả của các hành động khác trên mỗi yếu tố

Điều đó không có vẻ rất sâu sắc.

Thông thường, đệ quy cấu trúc không thể được đệ quy đuôi, mặc dù bất kỳ loại đệ quy nào cũng có thể được viết lại dưới dạng đệ quy đuôi (bằng chứng: nếu bạn chạy đệ quy gốc, các hành động được hoàn thành theo một thứ tự nhất định; tương đương với việc thực hiện chuỗi hành động cụ thể đó, như tôi đã thảo luận trước đó, là đệ quy đuôi).

Cây nhị phân hoặc ví dụ cặp ở trên chứng minh điều này: tuy nhiên bạn sắp xếp các cuộc gọi đệ quy trên các tiểu dự án, chỉ một trong số chúng có thể là hành động cuối cùng; có lẽ không ai, nếu kết quả của họ được kết hợp theo một cách nào đó (giả sử, bổ sung). Như Andrej Bauer nói trong câu trả lời của mình, điều này có thể xảy ra ngay cả khi chỉ có một cuộc gọi đệ quy, miễn là kết quả được sửa đổi. Nói cách khác, đối với mọi loại đối tượng không phải là những danh sách được liên kết hiệu quả (chỉ có một tiểu dự án hoàn toàn), đệ quy cấu trúc không phải là đệ quy đuôi.


1
Đó là sai lầm rằng đệ quy đuôi chỉ là về danh sách, tưởng tượng hoặc thực tế. Chẳng hạn, hoàn toàn có thể có đệ quy đuôi trên cây nhị phân. Tôi có thể thấy lý do tại sao một người nào đó nghĩ rằng đó là vì phần còn lại của danh sách là "cái đuôi" của nó.
Andrej Bauer

@AndrejBauer Tôi sẽ cảm thấy xấu hổ về điều này khi tôi hiểu chính xác những gì sai. Dường như tautological rằng đệ quy đuôi của biểu mẫu f x = (stuff defining x'); f x'giống như trình tự các nút trong danh sách được liên kết được xác định như l = modify f : l(theo kiểu Haskell-monad). Nó không chỉ là sự tương đồng về mặt thuật ngữ đối với tôi. Đối với đệ quy đuôi trên cây nhị phân, bạn có thể giải thích? Tôi chỉ có thể nghĩ về thực tế tuyến tính hóa từ đoạn thứ hai của tôi.
Ryan Reich

Không phải tất cả các cuộc gọi đệ quy đuôi là hình thức đó. Ví dụ, có thể có một số lệnh gọi đệ quy đuôi trong các nhánh khác nhau (của các câu lệnh tình huống hoặc một số như vậy). Thật tự nhiên hơn khi nghĩ về những người như chọn một con đường xuyên qua một cái cây . Cũng lưu ý rằng các cuộc gọi là đệ quy đuôi (hoặc không), vì vậy bạn có thể có f (f x)cuộc gọi bên ngoài flà đệ quy đuôi. Làm thế nào mà nó phù hợp với quan điểm rằng đó là tất cả về danh sách? Đây là một ví dụ khác: f : (Int -> Int) -> (Int -> Int)với f g 0 = g 42f g (n + 1) = f (f . g) n. Các khả năng là vô tận, và một số là hữu ích.
Andrej Bauer

@AndrejBauer Câu hỏi là về đệ quy đuôi thay vì chỉ gọi đuôi , vì vậy tôi sẽ không xem xét f (f x)áp dụng: trong đánh giá của f bên ngoài, bên trong không phải là một cuộc gọi đuôi (trừ khi f là danh tính). Các câu lệnh if có thể được viết lại một cách tầm thường không phân nhánh trong lệnh gọi đuôi : if (c) then f a else f b == let x = if (c) then a else b in f x. Ví dụ cuối cùng không hợp lệ vì f . gkhông đánh máy; ngay cả như vậy, nó vẫn sẽ không phải là đệ quy đuôi: f g = \n -> if n == 0 then g 42 else f (f . g) (n - 1)không phải là một lời kêu gọi f, mà là một lambda thực sự khác biệt. (tiếp theo)
Ryan Reich

Tôi thực sự nói rằng ví dụ đó là về đệ quy đuôi lẫn nhau , nghĩa là f g = h where { h 0 = g 42; h n = f (f . g) (n - 1) }, nhưng nếu bạn đưa nó vào cuộc thảo luận, thì bất kỳ hàm đệ quy nào , đuôi hay không, đều được chấp nhận và thuật ngữ này trở nên vô nghĩa.
Ryan Reich
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.