2013-01-13 11 views
6

The following Clojure code używa core.logic do rozwiązania tego samego problemu logicznego z tymi samymi celami w dwóch różnych zamówieniach. Ten wybór uporządkowania powoduje szybkie zakończenie, a drugi zawieszenie.Zamawianie celu w Clojure `core.logic`

(use `clojure.core.logic) 

;; Runs quickly. Prints (1 2 3). 
(clojure.pprint/pprint (run* [q] (fresh [x] (== x [1,2,3]) 
              (membero q x)))) 

;; Hangs 
(clojure.pprint/pprint (run* [q] (fresh [x] (membero q x) 
              (== x [1,2,3])))) 

Czy istnieje ogólne rozwiązanie lub powszechna praktyka, aby uniknąć tego problemu?

Odpowiedz

3

Jeśli zamierzasz używać membero, nie ma ogólnego rozwiązania tego problemu. Wywołanie membero ze świeżymi varami spowoduje wygenerowanie wszystkich (przeczytanych, nieskończonych) możliwych list, których członkiem jest q. Oczywiście listy większe niż 3 nie mają zastosowania - ale ponieważ używasz run*, będą nadal ślepo próbować list większych niż liczba 3, nawet jeśli każda z nich zawiedzie.

Możliwe jest napisanie lepszej wersji membero w nowszych wersjach core.logic przy użyciu infrastruktury więzów, ale szczegóły tego, jak to zrobić, prawdopodobnie ulegną zmianie w nadchodzących miesiącach. Dopóki nie ma solidnych publicznych api do definiowania ograniczeń, utknąłeś z subtelnymi problemami porządkowania i nie kończenia pracy, które sprawiają kłopot Prologowi.

7

Oto moje rozumienie:

Z core.logic, chcesz zmniejszyć przestrzeń poszukiwań tak wcześnie, jak to możliwe. Jeśli najpierw zostanie nałożone ograniczenie membero, uruchomienie rozpocznie się od przeszukania przestrzeni membero i wycofania po niepowodzeniu spowodowanym ograniczeniem . Ale przestrzeń membero jest OGROMNA, ponieważ ani q ani x nie jest zunifikowana ani przynajmniej ograniczona.

Ale jeśli umieścisz == ograniczenie pierwsze, bezpośrednio ujednolicić x z [1 2 3], a przestrzeń poszukiwań dla membero teraz jest wyraźnie ograniczony do elementów x.

+0

Co dokładnie szuka w '(membero q x)'? Czy X rzeczywiście jest iteracją wśród wszystkich możliwych kolekcji? Jakie obliczenia występują, gdy się zawiesi? – MRocklin

+1

@MRocklin, dokładnie. W rzeczywistości, jeśli wyobrazisz sobie kod dla 'membero', spróbuje zunifikować element z listą z tym elementem, a następnie rekurencyjnie zbudować listy, które zawierają element w dowolnej pozycji do nieskończoności. Teoretycznie uporządkowanie faktów nie jest potrzebne, ale wygodnie jest ograniczyć drzewo wyszukiwania. –