2015-03-18 11 views
6

Próbuję zrozumieć, jak działa Prolog. Używam SWI-Prolog. Oto fragment kodu:Prolog - argumenty nie są tworzone instancyjnie

forall(C1,C2) :- \+ (C1, \+ C2). 

foo(N) :- N < 10. 

bar(N) :- N > 5. 

foobar(N) :- forall(foo(N),bar(N)). 

To produkuje żądanego wyjścia, jeśli zrobię coś takiego:

?- foobar(5). 
false. 

Ale gdy próbuję zobaczyć wszystkie możliwe wartości pojawia się błąd:

?- foobar(N). 
ERROR: </2: Arguments are not sufficiently instantiated 

Co się tutaj dzieje?

+4

Opcja '/2' operatorzy wymagają, aby wszystkie argumenty mają specyficzne wartości (są instancja) w celu podjęcia pracy. Więc jeśli 'N' nie ma wartości (nie jest * instancja *), to' N <10' wygeneruje ten błąd. Jeśli próbujesz wygenerować możliwe wartości z pewnymi ograniczeniami, możesz użyć biblioteki CLPFD, możesz użyć 'N # <10', itd. – lurker

+0

@lurker Ok Widzę. Jak zmienić kod tak, aby wyprowadzał wszystkie możliwe liczby całkowite? I nie tylko sprawdza, czy argument spełnia warunek? Czy to możliwe? – akalikin

+0

@lurker ok, wielkie dzięki – akalikin

Odpowiedz

3

zasadzie piszesz program czek dla globalnej implikację:

forall N, if N < 10 then N > 5 

i chcesz wiedzieć, dla których domena N że trzyma.

Teraz poprawnie przepisać że w prologu jak:

\+ (N < 10, \+ (N > 5)). 

Ale jeśli spróbujesz dać, że zapytanie do prolog tłumacza, to wyświetli się błąd:

?- \+ (N < 10, \+ (N > 5)). 
ERROR: </2: Arguments are not sufficiently instantiated 

ponieważ argumenty < nie są tworzone instancjami. Zdarza się to samo z prostym zapytaniem, takim jak N < 3. Oczywiście, jeśli instancję przed zapytania, problem zniknie:

?- N=5, \+ (N < 10, \+ (N > 5)). 
false. 

(oświadczenie nie trzymać dla N = 5)

?- N=6, \+ (N < 10, \+ (N > 5)). 
N = 6. 

(ale to zachodzi dla n = 6) .

Można również umieścić predykat, który generuje wiele zadań dla N poprzez backtracking, zamiast tego N=6:

?- between(1, 12, N), \+ (N < 10, \+ (N > 5)). 
N = 6 ; 
N = 7 ; 
N = 8 ; 
N = 9 ; 
N = 10 ; 
N = 11 ; 
N = 12. 

ale dla dużej domeny, która będzie bardzo nieefektywne (będzie to wymagało backtracking dla każdego elementu domeny).

Jeśli chcesz uzyskać informacje na temat domen skończonych (tzn. Liczb całkowitych), możesz skorzystać z biblioteki CLPFD, zgodnie z sugestią @lurker. To podejście jest bardziej wydajne, ponieważ zawiera reguły dotyczące wnioskowania o odstępach czasu, przecinania w interwałach i wiele innych.

Trzeba zastąpić <, >, ,, \+ z CLP operatorów #<, #>, #/\, #\. Spróbujmy go:

?- use_module(library(clpfd)). 
?- #\ (N #< 10 #/\ #\ (N #> 5)). 
N+1#=_G11193, 
N#>=6#<==>_G11205, 
10#>=_G11193#<==>_G11217, 
_G11217 in 0..1, 
_G11217#/\_G11244#<==>0, 
_G11244 in 0..1, 
#\_G11205#<==>_G11244, 
_G11205 in 0..1. 

że może być nieco trudne do odczytania, ale wśród wielu innych rzeczy, to mówi wam odpowiedź, której szukasz, że to domena N: N #>= 6.

2

TL; DR. Prolog ma ładne właściwości algebraiczne, o ile pozostajesz w jego logicznie czystym rdzeniu.


Szczegółowe informacje można znaleźć następujące doskonałe odpowiedzi na pytania Prolog na StackOverflow:

Powiązane problemy