2011-09-24 36 views
9

Làm cách nào để thực hiện thao tác cho từng phần tử trong danh sách, theo thứ tự?hoạt động thực thi cho từng phần tử danh sách trong swi-prolog và các phần tử khác

Dựa trên hai nguồn sau đây:

  1. http://www.swi-prolog.org/pldoc/doc/swi/library/lists.pl
  2. http://www.swi-prolog.org/pldoc/doc_for?object=foreach/2

Tôi tưởng tượng tôi luôn luôn có thể dựa vào:

  • foreach(member(X, [1,2]), write(X)).

Đó là xác định và tôi có thể bọc thành phần/2 vị ngữ như tôi xin vui lòng trong các vị từ của riêng tôi và vẫn luôn lặp lại theo thứ tự?

Trả lời

16

Có, nhưng bạn phải lo lắng về vị từ của bạn không thành công. Nếu có thể, các phần tử còn lại trong danh sách sẽ không được xử lý bởi vì nó tạo ra một kết hợp chứ không phải là một vòng lặp do lỗi.

Tôi rất muốn sử dụng maplist/2 vì tôi cho rằng nó được sử dụng rộng rãi hơn foreach/2 nhưng tôi cũng chưa thấy tùy chọn này trước đây. :)

Chỉnh sửa: Hãy thảo luận những gì tôi muốn nói về các vòng lặp do lỗi.

Có hai phương pháp lặp nguyên thủy trong Prolog: vòng lặp đệ quy và lỗi. Nói rằng tôi muốn in ra mọi mục trong một danh sách. Phương pháp đệ quy sẽ trông như thế này:

print_all([]). 
print_all([X|Rest]) :- write(X), nl, print_all(Rest). 

Vì vậy, cho một danh sách như [1,2,3], điều này sẽ mở rộng như vậy:

print_all([1,2,3]) 
    write(1), nl, print_all([2,3]) 
    write(1), nl, write(2), nl, print_all([3]) 
     write(1), nl, write(2), nl, write(3), nl, print_all([]) 
     write(1), nl, write(2), nl, write(3), nl. 

Đây là cách member/2 thường thực hiện:

member(X, [X|_]). 
member(X, [_|Xs]) :- member(X, Xs). 

Vì vậy, bạn có thể thấy phương pháp đệ quy khá đơn giản và chung chung.

Phương pháp đơn giản nhưng hơi cau mày khác là mô phỏng sự thất bại trong việc tham gia vào cơ chế backtracking. Đây được gọi là một vòng lặp thất bại-driven và trông như thế này:

print_all(List) :- member(X, List), write(X), nl, fail. 
print_all(_). 

Khi bạn chạy phiên bản này của print_all/1, những gì xảy ra là nhiều hơn một chút phức tạp hơn so với việc mở rộng đơn giản.

print_all([1,2,3]) 
    member([1,2,3], 1) 
    write(1), nl 
     fail 
    retry member([1,2,3], 2) 
    write(2), nl 
     fail 
    retry member([1,2,3], 3) 
    write(3), nl 
     fail 
retry print_all(_) 
    true 

lời nói, các lực lượng fail Prolog để sao lưu đến cuối cùng điểm lựa chọn nó làm và cố gắng sử dụng các giải pháp tiếp theo. Vâng, write/1nl/0 không tạo điểm lựa chọn vì chúng chỉ có một giải pháp, nhưng member/2không có nhiều giải pháp — một giải pháp cho mỗi mục trong danh sách. Vì vậy, Prolog mất mỗi mục ra khỏi danh sách và in nó.Cuối cùng khi member/2 hết dung lượng, Prolog sao lưu vào điểm lựa chọn trước đó, là phần thứ hai của thuộc tính print_all/1, luôn luôn thành công. Vì vậy, đầu ra trông giống nhau. Tôi nghĩ mọi người ngày nay thường không thích sử dụng các vòng điều khiển thất bại, nhưng tôi không hiểu các đối số đủ tốt để vẹt chúng một cách hữu ích.

Một điều có thể giúp bạn xem điều gì đang xảy ra là sử dụng biến vị ngữ trace và bước qua việc mở rộng cả hai phiên bản và xem liệu bạn có thể hiểu được sự khác biệt hay không. Ký hiệu của tôi ở trên hoàn toàn được tạo cho câu trả lời này và có thể không rõ ràng.

Nhìn lại những gì tôi ban đầu được viết và câu hỏi thực tế của bạn:

  • foreach sẽ là xác định
  • member sẽ luôn lặp theo thứ tự, vì danh sách được định nghĩa theo cách như vậy mà bạn phải truy cập mỗi mục lần lượt

Hơn nữa, những ngày này ít nhất là trên SO bạn sẽ nhận được rất nhiều người nói với bạn để sử dụng maplist và ilk của nó, vì vậy nó có lẽ không chỉ đi làm, mà còn là một ý tưởng tốt.

+0

Tôi thấy sẽ xây dựng một danh sách với vòng lặp điều khiển không thành công của vị từ mà tôi muốn tất cả các giải pháp, sau đó ánh xạ danh sách qua vòng lặp để in chúng. Tôi nghĩ rằng sẽ cần một vòng lặp điều khiển lỗi ở đâu đó vì chương trình của tôi rất dựa trên bằng chứng nhiều hơn là dựa trên tính toán. – codeshot

+0

Nó luôn luôn có thể làm điều đó một trong hai cách. Tôi khuyên bạn nên tránh các vòng lặp điều khiển thất bại nếu bạn có thể, nhưng nếu nó có ý nghĩa hơn, sử dụng nó. –

+0

Việc tôi đọc tài liệu về danh sách bản đồ/2 là danh sách có thể được sắp xếp lại có nghĩa là các hành động sẽ được thực hiện theo thứ tự tùy ý. Điều đó có nghĩa là nó không giải quyết được vấn đề. Đệ quy có sự phức tạp không mô tả ý định của tôi nhưng tôi nghĩ foldl/4 thực hiện những gì tôi cần theo cách mô tả một cách hợp lý nếu tôi chỉ cung cấp một xung quanh áp dụng chấp nhận hai tham số bổ sung để tích lũy không có gì: hành động (A, _, _): gọi (A) – codeshot

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