I. NHÁT CẮT
I.2.1. Tạo đích giả bằng nhát cắ t
Giả sử ta đặt ra câu hỏi :
?- f( 1, Y ), 2 < Y.
Lúc này, Y nhận giá trị 0, đích thứ hai trở thành :
2 < 0
và gây ra kết quả No (thất bại) cho cả danh sách các đích còn lại, vì Prolog còn tiếp tục tiến hành thêm hai quá trình quay lui vô ích khác :
Hình I.2. Tại vị trí «Nhát cắt», các luật 2 và 3 đã biết trước thất bại.
Cả ba luật định nghĩa quan hệf có tính chất loại trừ lẫn nhau, chỉ có duy nhất một trong chúng là có thể thành công. Người lập trình biết điều này nhưng
Luật 1 Luật 2 Luật 3 Y = 0 Y = 2 Y = 4 Nhát cắt Thất bại Thất bại Thất bại f( 1, Y), 2 < Y. 1 < 3, 2 < 0 3 ≤ 1, 1 < 6, 2 6 ≤ 1, 2 < 4 2 < 0 + + + + + + + + + 3 6 X Y - - 4 - - 2 - -
Prolog lại không biết, cho nên cứ tiếp tục áp dụng tất cả các luật mặc dù đi đến thất bại. Trong ví dụ trên, luật 1 được áp dụng tại vị trí «Nhát cắt» và gây ra thất bại. Để tránh sự quay lui không cần thiết bắt đầu từ vị trí này, chúng ta cần báo cho Prolog biết một cách tường minh, bằng cách sử dụng một nhát cắt, ký hiệu bởi một dấu chấm than «!» thực chất là một đích giả (pseudo goal) được chèn vào giữa các đích thật khác. Chương trình hàm bậc thang được viết lại như sau :
f( X, 0) :- X < 3, !. % luật 1
f( X, 2) :-
3 =< X, X < 6, !. % luật 2
f( X, 4) :-
6 =< X. % luật 3
Nhát cắt ! sẽ cấm mọi quá trình quay lui từ vị trí xuất hiện của nó trong chương trình. Nếu bây giờ ta yêu cầu thực hiện đích :
?- f( 1, Y ), 2 < Y.
Prolog chỉ thực hiện nhánh trái nhất ứng với luật 1 trong hình trên, trả về kết quả thất bại vì xảy ra 2 < 0 mà không tiếp tục quay lui thực hiện các nhánh tương ứng với luật 2 và 3, do đã gặp nhát cắt !. Chương trình mới sử dụng nhát cắt chạy hiệu quả hơn chương trình cũ. Khi xảy ra thất bại, Prolog sẽ nhanh chóng dừng, mà không mất thời gian để thực hiện những việc vô ích khác. Sử
dụng nhát cắt trong một chương trình làm thay đổi nghĩa thủ tục nhưng không làm thay đổi nghĩa khai báo. Tuy nhiên sau đây ta sẽ thấy rằng nhát cắt có thể
làm mất đi nghĩa khai báo.