per confrontare il comportamento dei due predicati
conta1 e conta2 possiamo utilizzare
questi goal:
?- conta1(a,[a,b,c,a,b]). ?- conta2(a,[a,b,c,a,b]).
In questo caso tutti gli elementi della lista sono istanziati.
conta1 e conta2 si comportano nello stesso modo.
?- conta1(a,[a,X,Y,a,Z]). ?- conta2(a,[a,X,Y,a,Z]).
Questa volta nella lista ci sono degli elementi variabili
e per i due goal si ottengono risposte differenti.
conta2 avrà successo 5 volte, sia quando a
coincide con un atomo della lista, sia quando una variabile può
essere istanziata al valore a.
conta2 avrà successo solo 2 volte, perchè
la sua seconda clausola non si applica alle variabili non istanziate.
Nel programma che segue la prima clausola per conta_tutto
rappresenta la fine ricorsiona; per una lista vuota i conteggi sono
tutti a zero.
La seconda,la terza e la quarta clausola si riferiscono al conteggio
di atomi, interi e variabili.
L'ultima clausola, che puo essere raggiunta solo se non e' stata
utilizzata nessuna delle tre precedenti(per via del cut),
non conta oggetti di altro tipo, quali strutture e liste.
Se sottoponiamo all'interprete Prolog il segiente goal:
?- conta_tutto([a,b,X,Y,Z,10,12,31,2,f(c)],Atomi,Interi,Variabili).
otteniamo
Atomi=2 Interi=4 Variabili=3 Yes
Osservate che la struttura f(c) non viene contata.
%file: predefiniti/contatutti.pl % conta atomi, interi e variabili presenti in una lista% %lista vuota - i contatori vengono azzerati conta_tutto([],0,0,0). %conta un atomo conta_tutto([X|Resto],Atomi,Interi,Variabili) :- atom(X), !, conta_tutto(Resto,AtomiR,Interi,Variabili), Atomi is AtomiR + 1. %conta un intero conta_tutto([X|Resto],Atomi,Interi,Variabili) :- integer(X), !, conta_tutto(Resto,Atomi,InteriR,Variabili), Interi is InteriR + 1. %conta una variabile conta_tutto([X|Resto],Atomi,Interi,Variabili) :- var(X), !, conta_tutto(Resto,Atomi,Interi,VariabiliR), Variabili is VariabiliR + 1. % altro (struttura, lista) non lo conta conta_tutto([_xX|Resto],Atomi,Interi,Variabili) :- conta_tutto(Resto,Atomi,Interi,Variabili). % ?- conta_tutto([a,b,X,Y,Z,10,12,31,2,f(c)],Atomi,Interi,Variabili).
Il predicato scomponi deve estrarre la parte dell'atomo che
segue il prefisso, es:
?- scomponi(dia,dia116,N).
N=116
Yes
La lista di caratteri del prefisso, concatenata con la lista dei
caratteri restanti deve dare la lista dei caratteri dell'atomo completo.
Possiamo scomporre con name sia il prefisso che l'atomo.
Con conc, possiamo trovare la lista dei caratteri restanti,
che può essere riconvertita in atomo con la name.
%file: predefiniti/scomponiatomo.pl % scomponi(Prefix,Atomo,Resto) % controlla Resto e' quello che rimane di Atomo % dopo aver tolto il prefisso Prefix scomponi(Prefix,Atom,Resto):- % scompone Prefix name(Prefix,Plist), % scompone Atom name(Atom,Alist), % Plist e' la parte iniziale di Alist % Rlist contiene i caratteri restanti conc(Plist,Rlist,Alist), % ricostruisce un atomo da Rlist name(Resto,Rlist). % concatena due liste conc([],L,L). conc([X|L1],L2,[X|L3]) :- conc(L1,L2,L3). /* ?- prefisso(dia,dia241). ?- prefisso(lie,lie241). */
I goal per calcolare quadrati e cubi sono
% ?- mappaliste(quadrato,[0,1,2,3,4,5,6,7,8,9],L). % ?- mappaliste(cubo,[0,1,2,3,4,5,6,7,8,9],L).
Ecco una possibile definizione del predicato applica
applica(_,[N],N). applica(Op,[X,Y|Resto],Risultato) :- Espr =.. [Op,X,Y], Parziale is Espr, applica(Op,[Parziale|Resto],Risultato).
La prima clausola è il termine ricorsione: se la lista contiene
un solo numero,questo è il risultato.
Nella seconda clausola, si estraggono i primo due elementi della lista,
X e Y. Con l'operatore=..
si forma l'espressione <X><OP><Y>
che viene calcolata con l'operatore is. Il risultato così
ottenuto, viene inserito davanti agli elementi restanti della lista, nella
ricorsione.
%file: predefiniti/applica.pl
applica(_,[N],N).
applica(Op,[X,Y|Resto],Risultato) :-
Espr =.. [Op,X,Y],
Parziale is Espr,
applica(Op,[Parziale|Resto],Risultato).
% ?- applica('+',[2,3,5],N).
% ?- applica('-',[2,3,5],N).
% ?- applica('*',[2,3,5],N).
% ?- applica('/',[8,2,2],N).
Ecco i risultati forniti dall'interprete Prolog:
?- applica('+',[2,3,5],N).
N = 10
Yes
?- applica('-',[2,3,5],N).
N = -6
Yes
?- applica('*',[2,3,5],N).
N = 30
Yes
?- applica('/',[8,2,2],N).
N = 2
Yes
Le soluzioni per i predicati vince e minaccia sono riportate nel seguito:
% file predefiniti/filetto.pl
% gioco del filetto
/* rappresentazione della scacchiera:
s(x1,x2,x3,x4,x5,x6,x7,x8,x9)
dove xi puo' essere 'x' 'o' o una variabile
gli argomenti corrispondono a queste
posizioni sulla scacchiera
1 2 3
4 5 6
6 7 8
esempio di uso:
?- inizio.
?- mossa(x,3).
?- mossa(0,2).
?- mossa(x,5).
?- minaccia(X,Y).
......
......
*/
% inizio crea una scacchiera vuota
% e la asserisce nel database
inizio :-
retract(scacchiera(_)), % c'e' gia_ una scacchiera
functor(T,s,9), % T e' una scacchiera vuota
mostra(T),
assert(scacchiera(T)).
inizio :-
functor(T,s,9), % T e' una scacchiera vuota
mostra(T),
assert(scacchiera(T)).
% gestisce una mossa
% si mette Pezzo che puo' essere '0' o 'x'
% in Pos
mossa(Pezzo,Pos) :-
scacchiera(Scac), % configurazione memorizzata
vuoto(Pos,Scac), % la posizione deve essere libera
retract(scacchiera(Scac)), % elimina vecchia configurazione
arg(Pos,Scac,Pezzo), % istanzia l'argomento
assert(scacchiera(Scac)), % memorizza nuova configurazione
mostra(Scac), % visualizza
(vince(Scac,Giocatore), % controlla se mossa vincente
write(Giocatore),
write(' ha vinto!'),
nl; % ';' significa OR
true).
% la posizione Pos in Scac e' vuota
vuoto(Pos,Scac) :-
arg(Pos,Scac,Val), var(Val).
% la posizione Pos in Scac e' 'x'
croce(Pos,Scac) :-
arg(Pos,Scac,Val), nonvar(Val),Val=x.
% la posizione Pos in Scac e' '0'
zero(Pos,Scac) :-
arg(Pos,Scac,Val), nonvar(Val),Val=0.
% visualizzazione della scacchiera
riga([1,2,3]).
riga([4,5,6]).
riga([7,8,9]).
mostra(Scac) :-
riga([Pos1,Pos2,Pos3]),
mostra_pos(Pos1,Scac), tab(2),
mostra_pos(Pos2,Scac), tab(2),
mostra_pos(Pos3,Scac), tab(2),
tab(5),write([Pos1,Pos2,Pos3]),
nl,nl,
fail.
mostra(_).
mostra_pos(Pos,Scac):-
vuoto(Pos,Scac),
write('-').
mostra_pos(Pos,Scac):-
croce(Pos,Scac),
write(x).
mostra_pos(Pos,Scac):-
zero(Pos,Scac),
write(0).
% tabella delle posizioni allineate
allineate([1,2,3]). % righe
allineate([4,5,6]).
allineate([7,8,9]).
allineate([1,4,7]). % colonne
allineate([2,5,8]).
allineate([3,6,9]).
allineate([1,5,9]). % diagonali
allineate([3,5,7]).
% croce vince
vince(Scac,croce) :-
allineate([Pos1,Pos2,Pos3]),
croce(Pos1,Scac),
croce(Pos2,Scac),
croce(Pos3,Scac).
% zero vince
vince(Scac,zero) :-
allineate([Pos1,Pos2,Pos3]),
zero(Pos1,Scac),
zero(Pos2,Scac),
zero(Pos3,Scac).
% Giocatore minaccia Pos
% C'e' una posizione in cui completa la linea
minaccia(Giocatore,Pos) :-
scacchiera(Scac),
allineate(Posizioni),
controlla(Giocatore,Pos,Posizioni,Scac).
% controlla che ci siano 2 croci e
% una posizione vuota su una linea
controlla(croce,P1,[P1,P2,P3],Scac) :-
vuoto(P1,Scac),croce(P2,Scac),croce(P3,Scac).
controlla(croce,P2,[P1,P2,P3],Scac) :-
croce(P1,Scac),vuoto(P2,Scac),croce(P3,Scac).
controlla(croce,P3,[P1,P2,P3],Scac) :-
croce(P1,Scac),croce(P2,Scac),vuoto(P3,Scac).
% controlla che ci siano 2 zeri e
% una posizione vuota su una linea
controlla(zero,P1,[P1,P2,P3],Scac) :-
vuoto(P1,Scac),zero(P2,Scac),zero(P3,Scac).
controlla(zero,P2,[P1,P2,P3],Scac) :-
zero(P1,Scac),vuoto(P2,Scac),zero(P3,Scac).
controlla(zero,P3,[P1,P2,P3],Scac) :-
zero(P1,Scac),zero(P2,Scac),vuoto(P3,Scac).