Vì bạn có một số nền tảng trong logic, bạn có thể thấy hữu ích khi đọc các quy tắc dưới dạng công thức logic. Hãy thay thế (\ ==)/2 bởi dif/2 sau đó loại bỏ/3 đọc như sau:
remove([], _, [])
← true
remove([X | Xs], X, Ys)
← remove(Xs, X, Ys)
remove([Y | Xs], X, [Y | Ys])
← dif(X,Y)
∧ remove(Xs, X, Ys)
Lưu ý cách mũi tên hàm ý trỏ đến phần đầu của quy tắc. Điều đó có nghĩa là cơ thể của quy tắc là tiền lệ và người đứng đầu của quy tắc là hậu quả. Vì vậy, bạn đọc một quy tắc là: nếu phần thân của quy tắc là đúng thì đầu của quy tắc là đúng. Các mục tiêu trong các quy tắc được kết nối bằng cách kết hợp. Lưu ý rằng thực tế có true
là tiền đề, nghĩa là remove([], _, [])
luôn đúng. Mặt khác, nếu phần thân của quy tắc là sai thì quy tắc không thành công nhưng vị từ vẫn có thể thành công nếu phần thân của quy tắc khác là đúng. Nếu cơ thể của tất cả các quy tắc khác là sai thì vị từ không thành công. Vì vậy, có một số quy tắc cho một vị ngữ cấu thành logic hoặc: vị từ remove/3 thành công nếu rule1 HOẶC rule2 HOẶC rule3 thành công.
Khi bạn yêu cầu cú pháp cụ thể, nó cũng là cơ hội để làm quen với ký hiệu đầu và đuôi cho danh sách. Nghĩa là, bạn có thể viết phần tử đầu tiên (s) của một danh sách rõ ràng thì một danh sách constructor |
và phần còn lại của danh sách:
[1|Xs]
... danh sách bắt đầu với 1
và sau đó có một phần còn lại
[1,2|Xs]
... danh sách bắt đầu với 1
và 2
theo sau là một phần còn lại
[X|Xs]
... danh sách đã ít nhất một yếu tố tiếp theo là một phần còn lại
Lưu ý cách các yếu tố danh sách được phân cách bằng 012.trong khi phần còn lại của danh sách được phân tách bằng |
. Thuật ngữ sau |
thực sự là một danh sách và cũng có thể là một danh sách trống.Dưới đây là một số ví dụ cho các danh sách bình đẳng:
[1]
cũng giống như [1|[]]
[1,2]
= [1|[2]]
= [1|[2|[]]]
= [1,2|[]]
Đối với danh sách sau đây đã có 8 cách để viết nó:
[1,2,3]
= [1,2|[3]]
= [1|[2,3]]
= [1|[2|[3|[]]]]
= ...
Với những quan sát trên, bạn sẽ kiểm tra từng quy tắc một. Như @ lurker đã làm điều đó trong câu trả lời của mình, tôi sẽ không đi vào chi tiết. Tuy nhiên, tôi muốn nói thêm rằng nếu một quy tắc có một số mục tiêu, giống như quy tắc thứ 3 trong ví dụ của bạn, tôi thấy hữu ích khi đi bộ qua các mục tiêu cùng một lúc:
remove([Y | Xs], X, [Y | Ys]) :-
tử Y
của danh sách ban đầu cũng trong danh sách mà không X
NẾU ...
remove([Y | Xs], X, [Y | Ys]) :-
dif(X,Y),
... X
là khác nhau từ Y
VÀ ...
remove([Y | Xs], X, [Y | Ys]) :-
dif(X,Y),
remove(Xs, X, Ys).
... mối quan hệ giữ cho Xs
, X
và Ys
.
Vậy tại sao lại thay thế? Vị từ được xây dựng sẵn (\ ==)/2 chỉ thành công hoặc thất bại mà không có sự hợp nhất hoặc tác dụng phụ. Nó là tốt cho thử nghiệm bất bình đẳng hạn tại một thời gian nhất định nhưng không có bất kỳ tác dụng sau này. Hãy xem xét các truy vấn sau đây:
?- X=Y, X\==Y.
no
Đầu tiên các biến X
và Y
được thống nhất và sau đó kiểm tra cho bất bình đẳng thất bại. Nhưng:
?- X\==Y, X=Y.
X = Y
Đầu tiên kiểm tra sự bất bình đẳng thành công, nếu không Prolog thậm chí sẽ không xem xét mục tiêu thứ hai. Sau đó, X
và Y
được hợp nhất thành công. Đây là ý của tôi là không có hiệu lực sau này trên. Vì vậy, tất cả mọi thứ tôi đã viết ở trên về việc đọc các vị từ không thực sự có ý nghĩa với (\ ==)/2.
Là một phiên bản ngắn hơn tôi ném sau trong chiếc mũ, sử dụng if_/3 và =/3:
list_without_element([],[],_E).
list_without_element([X|Xs],L,E) :-
if_(X=E,L=Ys,L=[X|Ys]),
list_without_element(Xs,Ys,E).
hoàn hảo cảm ơn bạn, cú pháp đã được thực sự khó hiểu cho tôi và có vẻ là rất khác nhau từ cách tôi thường đọc vị ngữ. – user6248190
@ user6248190 Tôi bắt đầu bằng cách suy nghĩ về một mệnh đề vị ngữ như đã nói, * Như vậy là đúng ** nếu ** .... * theo sau là một chuỗi các điều kiện. – lurker
xin lỗi một điều nữa, là có một cách ngắn hơn để làm những gì loại bỏ vị ngữ đang làm gì? Tại sao có 3 dòng loại bỏ? – user6248190