2013-06-19 35 views
5

Trong Prolog, tôi thường giải quyết một vấn đề bằng cách cung cấp một khuôn mẫu (một cấu trúc chứa các biến) và sau đó thỏa mãn một tập hợp các ràng buộc trên nó. Một ví dụ nhỏ có thể là:Đáp ứng một tập hợp các mục tiêu trong Prolog

go(T) :- 
    T = [_, _, _], 
    member(cat, T), 
    member(dog, T), 
    member(mouse, T). 

Và trong thực tế các tập các ràng buộc được tạo ra một cách nào đó khác hơn là cố định, và tôi phải viết một vị đệ quy để đáp ứng từng chế lần lượt:

go(T) :- 
    T = [_, _, _], 
    findall(A, animal(A), As), 
    % satisy member(A, T) for each A in As 
    fill_in_animals(T, As) 

fill_in_animals(T, []). 
fill_in_animals(T, [A|Rest]) :- 
    member(A, T), 
    fill_in_animals(T, Rest). 

Lưu ý rằng câu hỏi của tôi không phải là về các ràng buộc liên quan đến danh sách, và thậm chí các tham số cho ràng buộc không phải lúc nào cũng dễ dàng được tạo ra như một danh sách được chuyển đến một vị từ trợ giúp tương đối đơn giản như được sử dụng ở trên. Trong thực tế, tôi tìm thấy người trợ giúp là một biến vị ngữ khá vô lý mà tôi viết mỗi lần, trong đó:

  1. Chấp nhận một mẫu, một số tham số được sử dụng cho ràng buộc (và do đó ràng buộc biến của mẫu với giá trị hữu ích), và một biến để chỉ ra ràng buộc nào.
  2. Tạo ra một ràng buộc để thỏa mãn trong lần lặp này, áp dụng nó vào mẫu.
  3. Đệ quy gọi chính nó để các ràng buộc còn lại có thể được thỏa mãn.

Điều tôi đang tìm kiếm là một biến vị ngữ dọc theo các dòng findall, v.v., sẽ đáp ứng một nhóm mục tiêu, cái này theo mục tiêu khác. Một cái gì đó như:

% satisfyall(:Goal) 
% backtracks on Goal but keeps all bindings from each fully satisfied goal. 

satisfyall((animal(A), member(A, T))) 

Câu trả lời tôi đang tìm không nhất thiết phải ở dạng này. Trong thực tế có thể có một mâu thuẫn giữa backtracking trên một mục tiêu và duy trì mỗi bộ bindings kết quả từ nó.

Tôi hy vọng tôi đã giải thích được vấn đề của mình để giải thích rõ ràng điều gì sẽ giúp ích. (Nếu không cho tôi biết.) Xin lỗi trước cho câu hỏi dài dòng!

Cập nhật (2 năm sau)

tôi sẽ thử nó ra sau ngày hôm nay và cập nhật câu hỏi của tôi!

Lưu ý rằng tôi không bao giờ nói tôi muốn cập nhật câu hỏi trong cùng một ngày như thử. ;-)

@CapelliC đã chỉ đạo cho tôi đi đúng hướng, và tôi đã tìm ra một mô hình mà có vẻ làm việc khá tốt:

?- Gs = [member(red),member(blue)], T = [_,_], foreach(member(G, Gs), call(G, T)). 
T = [red, blue] ; 
T = [blue, red] ; 
+2

[lambda.pl] (http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl) có thể giúp đỡ, nhưng tôi nghĩ rằng bạn nên đi với findall/3 – CapelliC

+0

Có lý do cụ thể nào lambda không được phân phối với SWI không? Tôi rất thích có thể 'use_module (thư viện (lambda))'! –

+0

@DanielLyons: Tôi có một số downvote khi tôi đã cố gắng trả lời câu hỏi này rất giống nhau :) – CapelliC

Trả lời

1

Bạn chắc chắn biết rằng backtracking sẽ cần để hoàn tác các thay đổi được thực hiện để hoạt động. Đó là cốt lõi của thuật toán Prolog, và nguồn gốc của Prolog power.

Đó cũng là điểm yếu, khi tính đến các tính toán thông thường hơn, giống như nhất thiết phải liên quan đến các tác dụng phụ hoặc vòng lặp.

Để tìm đúng cách để buộc các quy tắc của chúng tôi làm việc cùng một con đường xác định có thể khó khăn, có lẽ vì đó không phải là cách mà Prolog được cho là hoạt động.

Vâng, bây giờ, dừng rants triết học, chúng ta hãy xem những gì guru Prolog của đã được cung cấp cho chúng tôi: SWI-Prolog cung cấp thư viện (aggregate), nơi bạn tìm thấy foreach, mà tôi nghĩ rằng làm phần lớn những gì bạn đang sau:

?- foreach(animal(X), member(X,L)). 
L = [cat, dog, mouse|_G10698] . 

Nghiên cứu nội trang phức tạp này có thể cung cấp cho bạn một số ý tưởng để triển khai (sử dụng ?- edit(foreach). từ bảng điều khiển để kiểm tra nguồn).

Lưu ý rằng nó tách Máy phát điện và Mục tiêu, trong khi câu hỏi của bạn là vô vọng hợp nhất. Đó là tất nhiên cần để có thể quay lại chỉ trên phần máy phát điện.

BTW, cố gắng hiểu danh sách ví dụ nhỏ trong trang tài liệu. Nó quá phức tạp bởi dif/2, nhưng bạn thực sự cần nắm bắt được hành vi của các ràng buộc để có thể khái quát hóa các vị từ đệ quy của bạn.

HTH

+0

Xin lỗi vì đã trả lời muộn. Tôi nghĩ bạn đã đưa tôi đi đúng hướng. – Edmund

3

Tình hình bạn mô tả trong câu hỏi là một chút khác biệt so với chữ ký của thuộc tính satisfyall/1 bạn đã cung cấp. Không có backtracking tham gia vào ví dụ fill_in_animals, ít nhất là không liên quan đến các biến chảy ra khỏi go/1. Có thể có "backtacking petit" trong sự hài lòng của subgoals, nhưng mục tiêu tổng thể không thất bại trong khi để lại bindings nguyên vẹn.

Một giải pháp hữu ích và có thể không hữu ích là sử dụng maplist/2.Ví dụ, ví dụ của bạn rất dễ dàng để đạt được theo cách này:

?- length(L, 3), maplist(animal, L). 
L = [cat, cat, cat] ; 
L = [cat, cat, dog] ; 
L = [cat, cat, mouse] ; 
L = [cat, dog, cat] ; 
... 
L = [mouse, mouse, dog] ; 
L = [mouse, mouse, mouse]. 

Bạn có thể tiếp tục sử dụng một cơ sở dữ liệu cụ thể hóa bằng cách thêm chỉ là một vị ngữ:

% just flips the arguments of member/2 
memberof(L, A) :- member(A, L). 

Sau đó, chúng ta có thể sử dụng findall/3 để làm việc :

?- findall(A, animal(A), Animals), 
    length(L, 3), 
    maplist(memberof(Animals), L). 

Animals = [cat, dog, mouse], 
L = [cat, cat, cat] ; 
Animals = [cat, dog, mouse], 
L = [cat, cat, dog] ; 
Animals = [cat, dog, mouse], 
L = [cat, cat, mouse] ; 
... 
Animals = [cat, dog, mouse], 
L = [mouse, mouse, dog] ; 
Animals = [cat, dog, mouse], 
L = [mouse, mouse, mouse]. 

Điều này sẽ giải thích rõ tại sao lambda.pl sẽ trợ giúp. Bạn sẽ không cần vị helper, bạn chỉ có thể viết:

?- findall(A, animal(A), Animals), 
    length(L, 3), 
    maplist(\Animal^member(Animal, Animals), L). 

(chưa được kiểm tra)

Nếu bạn đang thực sự có ý định phá vỡ biến ràng buộc và unbinding, tôi nghĩ rằng bạn đang đi để tạo ra một gỡ lỗi cơn ác mộng cho chính mình, nhưng SWI-Prolog có một global variable facility bạn có thể sử dụng. Tôi mơ hồ nhớ lại việc đọc ở đâu đó rằng asserta/retract không đủ cho tác vụ này.

Tôi càng nghĩ về điều đó, tôi càng cảm thấy mình sẽ không thực hiện một cách có ý nghĩa satisfyall/1 khác với số maplist/2, nhưng tôi rất mong tìm ra tôi sai.

+0

Tôi không quen thuộc với lambda.pl, và tôi đã không nhận thức được về maplist, nhưng maplist dường như có được 80% con đường ở đó. Tôi sẽ thử nó sau ngày hôm nay và cập nhật câu hỏi của tôi! – Edmund

+0

Tôi hy vọng @hardmath hoặc một người nào khác nhìn thấy một cách để đến với 'satisfall/1' mà sẽ cho bạn phần còn lại của con đường đó. Tôi không thấy cách trực tiếp để sử dụng cấu trúc khuôn mẫu khác ngoài việc đơn giản dựa vào quy trình thống nhất thông thường. Hy vọng rằng những người khác có trí tưởng tượng tốt hơn và có thể nhìn thấy một con đường phía trước. :) –

+0

'Động vật' phải được khai báo trên toàn cầu:' danh sách bản đồ (Động vật + \ Thành viên động vật^(Động vật, Động vật), L) ' – false

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