Ricerca…


introduzione

Molti dei moderni sistemi Prolog sono in continuo sviluppo e hanno aggiunto nuove funzionalità per affrontare le carenze classiche della lingua. Sfortunatamente, molti libri di testo di Prolog e persino i corsi di insegnamento presentano ancora solo il prologo superato. Questo argomento ha lo scopo di illustrare come il Prolog moderno ha superato alcuni dei problemi e la sintassi piuttosto crufty che appare nel vecchio Prolog e potrebbe ancora essere introdotta.

CLP (FD) per l'aritmetica dei numeri interi

Tradizionalmente, Prolog eseguiva l'aritmetica usando gli operatori is e =:= . Tuttavia, diversi Prolog attuali offrono CLP (FD) (Constraint Logic Programming su Finite Domains) come alternativa più pulita per l'aritmetica dei numeri interi. CLP (FD) si basa sulla memorizzazione dei vincoli che si applicano a un valore intero e sulla combinazione di quelli in memoria.

CLP (FD) è un'estensione nella maggior parte dei Prolog che lo supportano, quindi deve essere caricato in modo esplicito. Una volta caricato, la sintassi #= può prendere il posto di entrambi is e =:= . Ad esempio, in SWI-Prolog:

?- X is 2+2.
X = 4.

?- use_module(library(clpfd)).
?- X #= 2+2.
X = 4.

A differenza di is , #= è in grado di risolvere equazioni semplici e unificare in entrambe le direzioni:

?- 4 is 2+X.
ERROR: is/2: Arguments are not sufficiently instantiated

?- 4 #= 2+X.
X = 2.

CLP (FD) fornisce la propria sintassi del generatore.

?- between(1,100,X).
X = 1;
X = 2;
X = 3...

?- X in 1..100.
X in 1..100.

Si noti che il generatore non viene effettivamente eseguito: viene memorizzato solo il vincolo dell'intervallo, pronto per essere combinato con vincoli successivi. Il generatore può essere forzato a eseguire (e vincoli di forza bruta) usando il predicato label :

?- X in 1..100, label([X]).
X = 1;
X = 2;
X = 3..

L'uso di CLP può consentire una riduzione intelligente dei casi di forza bruta. Ad esempio, utilizzando l'aritmetica dei numeri interi vecchio stile:

?- trace.
?- between(1,10,X), Y is X+5, Y>10.
...
Exit: (8) 6 is 1+5 ? creep
Call: (8) 6 > 10 ? creep
...
X = 6, Y = 11; ...

Il Prolog circola ancora sui valori 1-5 anche se è matematicamente dimostrabile dalle condizioni date che questi valori non possono essere utili. Utilizzando CLP (FD):

?- X in 1..10, Y #= X+5, Y #> 10.
X is 6..10,
X+5 #= Y,
Y is 11..15.

CLP (FD) esegue immediatamente i calcoli matematici e risolve gli intervalli disponibili. L'aggiunta di label([Y]) farà sì che X esegua il loop solo attraverso i valori utili 6..10. In questo esempio di giocattolo, questo non aumenta le prestazioni perché con un intervallo così piccolo come 1-10, l'elaborazione algebra impiega tutto il tempo che il ciclo avrebbe fatto; ma quando viene elaborato un numero maggiore di numeri, ciò può ridurre sensibilmente il tempo di calcolo.

Il supporto per CLP (FD) è variabile tra Prologs. Il migliore sviluppo riconosciuto di CLP (FD) è in SICStus Prolog, che è commerciale e costoso. SWI-Prolog e altri Prolog aperti spesso hanno qualche implementazione. Visual Prolog non include CLP (FD) nella sua libreria standard, sebbene siano disponibili librerie di estensioni per esso.

Forall invece dei loop pilotati da errori

Alcuni manuali "classici" di Prolog utilizzano ancora la sintassi del ciclo guidata da errori e soggetta a errori, in cui viene utilizzato un costrutto di fail per forzare il backtracking ad applicare un obiettivo a ogni valore di un generatore. Ad esempio, per stampare tutti i numeri fino a un determinato limite:

fdl(X) :- between(1,X,Y), print(Y), fail.
fdl(_).

La stragrande maggioranza dei Modern Prologs non richiede più questa sintassi, ma fornisce un predicato di ordine superiore per risolvere questo problema.

nicer(X) :- forall(between(1,X,Y), print(Y)).

Non solo è molto più facile da leggere, ma se un obiettivo che poteva fallire veniva usato al posto della stampa , il suo errore sarebbe stato rilevato e trasmesso correttamente - mentre i guasti degli obiettivi in ​​un ciclo guidato da errori sono confusi con l'errore forzato che guida il ciclo.

Visual Prolog ha uno zucchero sintattico personalizzato per questi loop, combinato con i predicati di funzione (vedi sotto):

vploop(X) :- foreach Y = std::fromTo(1,X) do
                 console::write(X)
             end foreach.

Anche se questo sembra un imperativo per il ciclo, segue ancora le regole Prolog: in particolare, ogni iterazione del foreach è il suo ambito.

Predicati di stile funzionale

Tradizionalmente in Prolog, le "funzioni" (con un output e input associati) venivano scritte come predicati regolari:

mangle(X,Y) :- Y is (X*5)+2.

Questo può creare la difficoltà che, se un predicato stile-funzione viene chiamato più volte, è necessario impostare variabili temporanee "a catena".

multimangle(X,Y) :- mangle(X,A), mangle(A,B), mangle(B,Y).

Nella maggior parte dei Prolog, è possibile evitare ciò scrivendo un operatore infisso alternativo da utilizzare al posto di is che espande le espressioni compresa la funzione alternativa.

% Define the new infix operator
:- op(900, xfy, <-).

% Define our function in terms of the infix operator - note the cut to avoid
% the choice falling through
R <- mangle(X) :- R is (X*5)+2, !.

% To make the new operator compatible with is..
R <- X :-
    compound(X),            % If the input is a compound/function
    X =.. [OP, X2, X3],     % Deconstruct it
    R2 <- X2,               % Recurse to evaluate the arguments
    R3 <- X3,
    Expr =.. [OP, R2, R3],  % Rebuild a compound with the evaluated arguments
    R is Expr,              % And send it to is
    !.
R <- X :- R is X, !.        % If it's not a compound, just use is directly

Ora possiamo scrivere:

multimangle(X,Y) :- X <- mangle(mangle(mangle(Y))).

Tuttavia, alcuni moderni Prolog vanno oltre e offrono una sintassi personalizzata per questo tipo di predicato. Ad esempio, in Visual Prolog:

mangle(X) = Y :- Y = ((X*5)+2).
multimangle(X,Y) :- Y = mangle(mangle(mangle(X))).

Si noti che l'operatore <- e il predicato dello stile funzionale di cui sopra si comportano ancora come relazioni - è legale per loro avere punti di scelta ed eseguire più unificazione. Nel primo esempio, evitiamo questo usando tagli. In Visual Prolog, è normale utilizzare la sintassi funzionale per le relazioni ei punti di scelta vengono creati nel modo normale - ad esempio, l'obiettivo X = (std::fromTo(1,10))*10 riesce con i binding X = 10 , X = 20, X = 30, X = 40, ecc.

Dichiarazioni flusso / modalità

Quando si programma in Prolog non è sempre possibile, o desiderabile, creare predicati che unificano per ogni possibile combinazione di parametri. Ad esempio, il predicato between(X,Y,Z) che esprime che Z è numericamente tra X e Y. È facilmente implementabile nei casi in cui X, Y e Z sono tutti vincolati (o Z è tra X e Y o non lo è), o dove X e Y sono vincolati e Z è libero (Z si unifica con tutti i numeri tra X e Y, o il predicato fallisce se Y <X); ma in altri casi, ad esempio dove X e Z sono legati e Y è libero, esiste potenzialmente un numero infinito di unificazioni. Sebbene questo possa essere implementato, di solito non lo sarebbe.

Dichiarazione di flusso o dichiarazioni di modalità consentono una descrizione esplicita di come si comportano i predicati quando vengono chiamati con diverse combinazioni di parametri associati. Nel caso di between , la dichiarazione sarebbe:

%! between(+X,+Y,+Z) is semidet.
%! between(+X,+Y,-Z) is nondet. 

Ogni linea specifica un potenziale modello di chiamata per il predicato. Ogni argomento è decorato con + per indicare i casi in cui è vincolato, o - per indicare i casi in cui non lo è (ci sono anche altre decorazioni disponibili per tipi più complessi come tuple o liste che possono essere parzialmente rilegate). La parola dopo è indica il comportamento del predicato in questo caso, e può essere uno dei seguenti:

  • det se il predicato riesce sempre senza punto di scelta. Ad esempio add(+X,+Y,-Z) è det perché aggiungendo due numeri X e Y avrà sempre esattamente una risposta.
  • semidet se il predicato ha esito positivo o negativo, senza alcun punto di scelta. Come sopra, between(+X,+Y,+Z) è semidet perché Z è tra X e Y oppure non lo è.
  • multi se il predicato ha sempre successo, ma può avere punti di scelta (ma potrebbe anche non esserlo). Ad esempio, factor(+X,-Y) sarebbe multi perché un numero ha sempre almeno un fattore - se stesso - ma potrebbe avere di più.
  • nondet se il predicato può avere successo con punti di scelta o fallire. Ad esempio, between(+X,+Y,-Z) è nondet perché potrebbero esserci diverse possibili unificazioni di Z ai numeri tra X e Y, oppure se Y <X allora non ci sono numeri tra loro e il predicato fallisce.

Le dichiarazioni di flusso / modalità possono anche essere combinate con l'etichettatura degli argomenti per chiarire cosa significano i termini o con la digitazione. Ad esempio, between(+From:Int, +To:Int, +Mid:Int) is semidet .

Nei puri Prolog, le dichiarazioni di flusso e modalità sono facoltative e utilizzate solo per la generazione di documentazione, ma possono essere estremamente utili per aiutare i programmatori a identificare la causa degli errori di istanziazione.

In Mercury, le dichiarazioni e i tipi di flusso e modalità sono obbligatori e vengono convalidati dal compilatore. La sintassi utilizzata è come sopra.

In Visual Prolog anche le dichiarazioni e i tipi di flusso e modalità sono obbligatori e la sintassi è diversa. La dichiarazione di cui sopra sarebbe scritta come:

between : (int From, int To, int Mid) determ (i,i,i) nondeterm (i,i,o).

Il significato è lo stesso di sopra, ma con le differenze che:

  • Le dichiarazioni di flusso / modalità sono separate dalle dichiarazioni di tipo (poiché si presume che il flusso / la modalità per un singolo predicato non varieranno con il sovraccarico di tipo);
  • i e o sono usati per + e - e sono abbinati ai parametri basati sull'ordinamento;
  • I termini usati sono diversi. det diventa procedure , semidet diventa determ e nondet diventa nondeterm ( multi è ancora multi ).


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow