Predicati Predefiniti

Operazioni su termini e strutture

File: predefiniti/contaatomi.pl

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.

file: predefiniti/contatutti.pl
Conta atomi, interi e variabili presenti in una lista.

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

file: predefiniti/scomponiatomo.pl

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).
*/

predefiniti/mappaliste.pl

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

file: predefiniti/applica.pl
Applica un operatore aritmetico ad una lista

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

Filetto

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