2015-03-18 23 views
6

Sto cercando di capire come funziona Prolog. Sto usando SWI-Prolog. Ecco un po 'di codice:Prolog - Gli argomenti non sono istanziati

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

foo(N) :- N < 10. 

bar(N) :- N > 5. 

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

Produce uscita desiderata se faccio qualcosa di simile:

?- foobar(5). 
false. 

Ma quando cerco di vedere tutti i valori possibili ottengo un errore:

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

Cosa sta succedendo qui?

+4

Il '/2' operatori richiedono che tutti gli argomenti hanno valori specifici (sono istanziati), al fine di lavorare. Quindi se 'N' non ha un valore (non è * istanziato *) allora' N <10' genererà quell'errore. Se stai cercando di generare valori con determinati vincoli, potresti voler usare la libreria CLPFD, quindi puoi usare 'N # <10', ecc. – lurker

+0

@lurker Ok, capisco. Come cambierei il codice in modo che produca tutti i numeri interi possibili? E non solo controlla se l'argomento soddisfa la condizione? È possibile? – akalikin

+0

ok @lurker, grazie mille – akalikin

risposta

3

In sostanza si sta scrivendo un programma il controllo per un implicazione globale:

forall N, if N < 10 then N > 5 

e volete sapere per quale dominio di N che contiene.

Ora è riscrivere correttamente che nel prologo come:

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

Ma se si tenta di dare quel query per l'interprete Prolog, il risultato sarà l'errore:

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

perché gli argomenti di < non sono istanziati. Succede la stessa cosa con una semplice query come N < 3. Naturalmente, se si crea un'istanza prima la query, il problema scompare:

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

(la dichiarazione non vale per N = 5)

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

(ma vale per N = 6) .

Si potrebbe anche mettere un predicato che genera più assegnazioni per N via backtracking, al posto di quella N=6:

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

ma per un grande dominio, che sta per essere altamente inefficiente (che richiederà backtracking per ogni elemento del dominio).

Se si desidera ragionare su domini finiti (cioè numeri interi), è possibile utilizzare la libreria CLPFD come suggerito da @lurker. Questo approccio è più efficiente, perché ha regole per il ragionamento su intervalli, intersezioni su intervalli e molte altre.

si deve sostituire <, >, ,, \+ con gli operatori CLP #<, #>, #/\, #\. Proviamo:

?- 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. 

che potrebbe essere un po 'difficile da leggere, ma tra le tante altre cose, che ti sta dicendo la risposta che state cercando, che è il dominio di N: N #>= 6.

2

TL; DR. Prolog ha buone proprietà algebriche a patto che si attacchi al suo core logicamente puro.


Per ulteriori informazioni, leggere le seguenti eccellenti risposte alle domande su StackOverflow Prolog:

Problemi correlati