Câu trả lời trực quan là nếu bạn không có các vòng lặp không giới hạn và bạn không có đệ quy và bạn không có goto, các chương trình của bạn sẽ chấm dứt. Điều này không hoàn toàn đúng, có nhiều cách khác để lén không chấm dứt, nhưng nó đủ tốt cho hầu hết các trường hợp thực tế. Tất nhiên điều ngược lại là sai, có những ngôn ngữ với các cấu trúc này không cho phép các chương trình không kết thúc, nhưng chúng sử dụng các loại hạn chế khác như hệ thống loại tinh vi.
Đệ quy
Một hạn chế phổ biến trong các ngôn ngữ kịch bản là để ngăn chặn đệ quy một cách linh hoạt: nếu A gọi B gọi C gọi các cuộc gọi A, thì trình thông dịch (hoặc trình kiểm tra, trong trường hợp của bạn) từ bỏ hoặc báo hiệu lỗi, ngay cả khi đệ quy thực sự có thể chấm dứt. Hai ví dụ cụ thể:
Bộ tiền xử lý C để lại một macro nguyên vẹn trong khi nó đang mở rộng macro đó. Việc sử dụng phổ biến nhất là xác định trình bao bọc xung quanh hàm:
#define f(x) (printf("calling f(%d)\n", (x)), f(x))
f(3);
Điều này mở rộng đến
(printf("calling f(%d)\n", (3)), f(3))
Đệ quy lẫn nhau cũng được xử lý. Một hậu quả là bộ tiền xử lý C luôn chấm dứt, mặc dù có thể xây dựng các macro với độ phức tạp thời gian chạy cao.
#define f0(x) x(x)x(x)
#define f1(x) f0(f0(x))
#define f2(x) f1(f1(x))
#define f3(x) f2(f2(x))
f3(x)
Shell Unix mở rộng bí danh theo cách đệ quy, nhưng chỉ cho đến khi chúng gặp phải một bí danh đã được mở rộng. Một lần nữa, mục đích chính là xác định bí danh cho một lệnh có cùng tên.
alias ls='ls --color'
alias ll='ls -l'
nn
Có nhiều kỹ thuật tổng quát hơn để chứng minh rằng các cuộc gọi đệ quy chấm dứt, chẳng hạn như tìm một số nguyên dương luôn giảm từ một cuộc gọi đệ quy sang cuộc gọi tiếp theo, nhưng chúng khó phát hiện hơn. Họ thường khó kiểm chứng, huống chi là suy luận.
Vòng lặp
for
mn
Đặc biệt, với các vòng lặp (cộng với các cấu trúc ngôn ngữ hợp lý như điều kiện), bạn có thể viết tất cả các hàm đệ quy nguyên thủy và ngược lại. Bạn có thể nhận ra các hàm đệ quy nguyên thủy theo cú pháp (nếu chúng được viết theo cách không được kiểm soát), bởi vì chúng không sử dụng vòng lặp while hoặc goto hoặc đệ quy hoặc thủ thuật khác. Các hàm đệ quy nguyên thủy được đảm bảo chấm dứt và hầu hết các tác vụ thực tế không vượt quá đệ quy nguyên thủy.