Salta ai contenuti. | Salta alla navigazione

Strumenti personali

Propia

...le inviamo il testo di un esercizio preso tra quelli da lei proposti (esercizio n°2, pag.5) relativo ai Contenitori contententi diversi tipi di liquidi. Quella che le inviamo e' la versione svolta da noi, ma non riusciamo a risolvere l'errore, che però pensiamo di aver individuato nella funzione "contatore" al momento in cui si effettua il test di uguaglianza, in quanto invece di effettuare un vero e proprio test effettua un'assegnazione.

:- lib(fd).
:- lib(propia).

contenuto(L,X) :- length(L,N),
        length(X,N),
        X::[latte,vino,acqua,vuoto],
        quantita(L,X,vino,Qvino),
        quantita(L,X,acqua,Qacqua),
        quantita(L,X,latte,Qlatte),
        contatore(X,latte,Clatte),
        contatore(X,acqua,Cacqua),
        contatore(X,vino,Cvino),
        contatore(X,vuoto,Cvuoto),
        Clatte#=1,      
        Cvuoto#=1,
        Cacqua#\=0,
        Cvino#\=0,
        Qvino#=Qacqua*2,
        Qacqua#=Qlatte*2,
        labeling(X).

contatore([X],Tipo,1) :- X==Tipo,!.
contatore([_],_,0) :-!.

contatore([H|T],Tipo,N) :- H==Tipo,!,
                contatore(T,Tipo,N1),
                N is N1+1.

contatore([_|T],Tipo,N) :- contatore(T,Tipo,N1),
                N is N1.
.....

quantita e contatore sono predicati Prolog, che non utilizzano i vincoli. E' possibile trasformarli in vincoli con la libreria Propia che voi, giustamente, caricate, però bisogna anche fare qualche piccola modifica:

  1. quando si invoca il predicato, bisogna mettere infers fd, altrimenti il predicato viene invocato normalmente (senza Propia); ad esempio:
    contenuto(L,X) :- length(L,N),
            length(X,N),
            X::[latte,vino,acqua,vuoto],
            quantita(L,X,vino,Qvino) infers fd,
            quantita(L,X,acqua,Qacqua) infers fd,
        ...
    
  2. La libreria Propia per trasformare il predicato in vincolo, invoca il predicato e trova tutte le risposte possibili, poi ne fa l'unione. Ad esempio, se il predicato è:
        p(1,1).
        p(1,2).
    
    ed invoco p(X,Y) infers fd, Propia invoca il goal p(X,Y) e trova le due soluzioni (X=1,Y=1) e (X=1,Y=2), poi fa l'unione dei domini nei 2 casi ed ottiene che X=1 e Y :: [1,2]. Questo funziona bene se non ci sono predicati extralogici, ma se mettessi
        p(1,1):-!.
        p(1,2).
    
    Propia troverebbe solo la prima soluzione, perché la seconda viene tagliata dal cut. Stesso discorso per il predicato extralogico == . Ad es:
        p(1,Y):- Y==1.
        p(1,2).
    
    Quando Propia invoca il predicato p(X,Y), la prima clausola fallisce (perché Y non è ancora ground), e solo la seconda ha successo. Lo stesso discorso vale per il predicato is, che se ha il termine alla destra non istanziato fallisce (o dà errore).

    Propia va invece particolarmente d'accordo con i vincoli della libreria fd, quindi conviene usare #= al posto di is. Al posto del cut, si possono mettere condizioni mutuamente esclusive. In sintesi, cambierei il predicato "contatore" più o meno in questo modo:

    contatore([X],Tipo,1) :- X#=Tipo.
    contatore([X],Tipo,0) :- X#\=Tipo.
    
    contatore([H|T],Tipo,N) :- H#=Tipo,
                    contatore(T,Tipo,N1),
                    N #= N1+1.
    
    contatore([H|T],Tipo,N) :- H #\= Tipo, contatore(T,Tipo,N1),
                    N #= N1.
    
    Ho tolto tutti i cut ed ho inserito dei vincoli di diverso quando voglio escludere che la clausola venga selezionata se la precedente ha successo. Questo ha l'effetto positivo che ogni clausola ha senso a sé stante. is e == sono stati sostituiti da vincoli.