2016-07-22 20 views
6

Bài tập 09 trên trang này http://www.ic.unicamp.br/~meidanis/courses/mc336/2009s2/prolog/problemas/ yêu cầu tạo một biến vị ngữ mà gói các phần tử lặp lại vào các danh sách con.`var (A)` và thứ tự thực hiện

Một giải pháp đơn giản là đơn giản

pack([], []). 
pack([H|T], [I|U]) :- 
    split(H, T, I, P), 
    pack(P, U). 

nơi chia được split(Head, Tail, HeadGroup, Rest) được định nghĩa là

split(A, [], [A], []). 
split(A, [B|T], [A], [B|T]) :- A \= B. 
split(A, [A|T], [A|U], B) :- split(A, T, U, B). 

mà hoạt động tốt và có khá nhiều phù hợp với giải pháp dụ được cung cấp trên trang web nêu trên .

Trường hợp giải pháp này không thành công là các truy vấn như pack(X, [[a], [b, b]]).. Sự tương ứng giữa hai bộ giải pháp là tính từ (đối với mỗi A trong pack(A, B) có một và chỉ một B), do đó phải có giải pháp tốt hơn.

Một cách để giải quyết nó là để thay đổi thứ tự đánh giá, giúp prolog để chọn chi nhánh không vô hạn tùy thuộc vào loại đối số như sau

pack([], []). 
pack(A, B) :- 
    (var(A) -> 
    A = [H|T], 
    B = [I|U], 
    pack(P, U), 
    split(H, T, I, P) 
    ; A = [H|T],                                                         
    B = [I|U], 
    split(H, T, I, P), 
    pack(P, U) 
). 

Hai câu hỏi về vấn đề này.

Thứ nhất, điều này là không thể tin được xấu xí, vậy có cách nào tốt hơn để chọn thứ tự các quy tắc tùy thuộc vào loại đối số không?

Thứ hai, có lẽ là câu hỏi phức tạp hơn nhiều, có cách nào để viết lại giải pháp mà không cần var(A) và nếu không phải lý do?

Trả lời

4

Từ một điểm khai báo trên, cấu trúc không đơn điệu như var/1 và   (\=)/2 rất vấn đề.

Tại sao? Check it out:

?- var(A), A=a. 
A = a. 

?- A=a, var(A). 
false. 

Vì vậy, điều này phá vỡ hoán của kết hợp, đó là một trong những thuộc tính cốt lõi chúng tôi dựa vào khi thực sự luận về các chương trình logic.

Điều gì về (\=)/2, bạn nghĩ nào sẽ thể hiện rằng hai cụm từ khác nhau? Check it out:

 
?- X \= Y. 
false. 

Không có hai thuật ngữ khác nhau tồn tại, đúng không? Có vẻ hơi lạ với tôi, để nói ít nhất, vì vậy rõ ràng vị ngữ thực sự có nghĩa là cái gì khác.

May mắn thay, trong trường hợp của bạn, giải pháp là rất dễ dàng. Chỉ cần sử dụng ràng buộc thuần túy dif/2 để biểu thị rằng hai cụm từ là khác nhau. Xem để biết thêm thông tin. Bạn chỉ phải thay đổi một dòng mã   để làm cho giải pháp của bạn tổng quát hơn nhiều.Thay vì:

split(A, [B|T], [A], [B|T]) :- A \= B. 

chỉ cần sử dụng dif/2:

 
split(A, [B|T], [A], [B|T]) :- dif(A, B). 

Với thay đổi này, ví dụ của bạn hoạt động hoàn toàn như mong đợi:

?- pack(X, [[a], [b, b]]). 
X = [a, b, b] ; 
false. 

Lưu ý rằng các tài liệu Prolog hiện tại là cách lỗi thời và hầu hết các giải pháp như vậy đến từ thời điểm dif/2 thậm chí không khả dụng hầu hết các hệ thống Prolog, chắc chắn không có trong các hệ thống miễn phí.

+4

Thiên tài thuần khiết! Với 'dif' nó bây giờ thậm chí có thể giải quyết những thứ điên rồ như' gói (A, [X, [b]]). – vasily

+2

Gonna xem lại tất cả các giải pháp trước của tôi. – vasily

+4

Vâng, đúng thế. 'dif/2' đã có sẵn ngay cả trong hệ thống Prolog đầu tiên, sau đó bởi và lớn bị bỏ qua bởi những người triển khai, và bây giờ ngày càng trở nên phổ biến trong việc triển khai một lần nữa. Dù sao đi nữa, lý luận về mọi hướng là một trong những điểm thu hút chính của lập trình quan hệ, vì vậy hãy sử dụng 'dif/2' để diễn tả sự bất bình đẳng trong một cách âm thanh và tổng quát. – mat

Các vấn đề liên quan