2013-08-20 11 views
12

Próbuję zrozumieć, jak utworzyć serię wartości z predykatu Prolog na backtrackingu. Wbudowany predykat between/3 wygeneruje wszystkie liczby całkowite w zakresie po jednym na raz podczas cofania, więc przykład tego, jak jest napisane, może mi pomóc w moim zadaniu.Czy możesz napisać od/3 w czystym prologu?

Szukałem implementacji w istniejącym systemie Prolog, ale implementacja between/3 dla GNU Prolog jest funkcją C, a sztuczka polega na tym, że wywołuje on inną funkcję C "Pl_Create_Choice_Point", która pozwala jej tworzyć dodatkowe wartości w cofanie.

Odpowiedz

12
bet(N, M, K) :- N =< M, K = N. 
bet(N, M, K) :- N < M, N1 is N+1, bet(N1, M, K). 

w akcji:

$ swipl 
?- [bet]. 
% bet compiled 0.00 sec, 1,064 bytes 
true. 

?- bet(1,5, K). 
K = 1 n 
K = 2 n 
K = 3 n 
K = 4 n 
K = 5 n 
false. 

Jeśli używasz cięcie, można zapobiec ostatecznej porażki wyszukiwania i odzyskiwania dokładnie polecenie wbudowane między/3 zachowań:

bet(N, M, K) :- N < M, K = N. 
bet(N, M, K) :- N == M, !, K = N. 
bet(N, M, K) :- N < M, N1 is N+1, bet(N1, M, K). 

W akcji :

?- [bet]. 
% bet compiled 0.00 sec, 416 bytes 
true. 

?- between(1,5,K). 
K = 1 n 
K = 2 n 
K = 3 n 
K = 4 n 
K = 5. 

?- [bet]. 
% bet compiled 0.00 sec, 240 bytes 
true. 

?- bet(1,5,K). 
K = 1 n 
K = 2 n 
K = 3 n 
K = 4 n 
K = 5. 
+0

Twoja początkowa wersja była nieco lepsza, ponieważ nie zawiodła na końcu. –

+0

Dzięki. Naprawiono wyświetlanie obu. – seanmcl

6

Co tak naprawdę jesteś Sking to jak stworzyć punkt wyboru. Otrzymasz rozwiązanie, gdy pomyślnie ujednolicisz. Tak dzieje się w pierwszym orzeczniku @ seanmcl:

bet(N, M, K) :- N =< M, K = N. 

Aby uzyskać punkt wyboru, musisz mieć alternatywę. Istnieją tylko dwa sposoby uzyskania alternatywy w Prologu: z wyraźnym "lub": ; lub poprzez podanie innej reguły. Kod @ seanmcl daje kolejną regułę, która jest idiomatyczna dla tej sytuacji.

Aby podać inny przykład, member/2 generuje rozwiązanie dla każdego elementu na liście, ale nie ma funkcji magia C potrzebne, zaledwie dwie zasady:

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

Spójrzmy na to, co dzieje się tutaj z member(X, [1,2]). Najpierw używana jest pierwsza reguła, a [X|_] jest zunifikowana z [1,2], produkując X=1, _=[2]. Jest to udana unifikacja, więc powstaje rozwiązanie. Jeśli to się nie powiedzie (np. Przez naciśnięcie klawisza ; na konsoli), inicjowane jest wycofywanie. Następny punkt wyboru znajduje się pomiędzy dwiema regułami, więc wprowadzana jest następna reguła. [_|Xs] łączy się z [1,2], wywołując powiązanie Xs=[2], a następnie member(X, [2]). Po ponownym wejściu te same decyzje mogą zostać ponownie podjęte, więc stosowana jest pierwsza reguła member(X, [X|_]) i powstaje powiązanie X=2. To jest rozwiązanie. Jeśli ponownie wykonasz powrót, uzyskasz nieszkodliwą awarię, ponieważ żadna z reguł nie zostanie zunifikowana z [].

Mam nadzieję, że pomoże to trochę zrozumieć sytuację.

+2

Niezłe wyjaśnienie. – seanmcl