Trên thực tế bạn nên phá vỡ chức năng đầu tiên:
Một vòng lặp có một vài phần:
tiêu đề và xử lý trước vòng lặp. Có thể khai báo một số biến mới
điều kiện, khi dừng vòng lặp.
cơ thể vòng lặp thực tế. Nó thay đổi một số biến tiêu đề và/hoặc các tham số được truyền vào.
cái đuôi; Điều gì xảy ra sau vòng lặp và kết quả trả về.
Hoặc để viết nó ra:
foo_iterative(params){
header
while(condition){
loop_body
}
return tail
}
Sử dụng các khối này để thực hiện cuộc gọi đệ quy khá đơn giản:
foo_recursive(params){
header
return foo_recursion(params, header_vars)
}
foo_recursion(params, header_vars){
if(!condition){
return tail
}
loop_body
return foo_recursion(params, modified_header_vars)
}
Et voilà; một phiên bản đệ quy đuôi của bất kỳ vòng lặp. breaks và continues trong thân vòng lặp vẫn sẽ phải được thay thế bằng return tail và trả về foo_recursion(params, modified_header_vars) khi cần nhưng đủ đơn giản.
Đi theo con đường khác phức tạp hơn; một phần vì có thể có nhiều cuộc gọi đệ quy. Điều này có nghĩa là mỗi lần chúng ta bật một khung stack có thể có nhiều nơi chúng ta cần tiếp tục. Ngoài ra, có thể có các biến mà chúng ta cần lưu trong cuộc gọi đệ quy và các tham số ban đầu của cuộc gọi.
Chúng ta có thể sử dụng một công tắc để làm việc xung quanh đó:
bar_recurse(params){
if(baseCase){
finalize
return
}
body1
bar_recurse(mod_params)
body2
bar_recurse(mod_params)
body3
}
bar_iterative(params){
stack.Push({init, params})
while(!stack.empty){
stackFrame = stack.pop()
switch(stackFrame.resumPoint){
case init:
if(baseCase){
finalize
break;
}
body1
stack.Push({resum1, params, variables})
stack.Push({init, modified_params})
break;
case resum1:
body2
stack.Push({resum2, params, variables})
stack.Push({init, modified_params})
break;
case resum2:
body3
break;
}
}
}