Si dice lista, una sequenza ordinata di un qualunque numero di elementi; gli elementi di una lista possono essere atomi, strutture, liste o qualunque altro tipo di dato. L'ordine in cui i termini si susseguono è importante; per esempio, la lista [a,b,c,d] è differente dalla lista [a,c,d,b] anche se singolarmente gli elementi che vi compaiono sono gli stessi.
Il modo abituale di rappresentare liste in Prolog è il seguente:
[genova,milano,roma][10,20,[30,40],cinquanta][a,b,[C,D,[e]]][ ]
È importante sottolineare i seguenti fatti: è possibile avere, come si può notare dagli esempi, liste di liste di liste... senza alcun limite teorico al livello di annidamento; nelle liste possono comparire anche variabili (come nella terza lista dell'esempio precedente); esse vengono trattate esattamente come le normali variabili Prolog.
In generale nell'ambito di una lista possibile individuare due parti strutturalmente significative, abitualmente note come testa e coda. Con il termine testa viene indicato il primo elemento della lista, e con il termine coda tutto ciò che resta della lista stessa, tolto il primo elemento. Consideriamo per esempio, le quattro liste precedente mente introdotte, per le quali testa e coda sono così definite:
LISTA TESTA CODA [genova,milano,roma]genova[milano,roma][10,20,[30,40],cinquanta]10[20,[30,40],cinquanta][a,b,[C,D,[e]]]a[b,[C,D,[e]]][ ]--
L'ultima lista, essendo priva di elementi, non possiede nè una testa nè una coda. Dovreste notare che la struttura della testa di una lista è quella del suo primo elemento, ovvero se il primo elemento di una lista è un'atomo, la sua testa sarà un atomo, se è una variabile sarà una variabile, se è una lista sarà una lista, e così via. Per quanto riguarda invece la coda, essa è sempre e comunque una lista che racchiude gli elementi restanti. Nel caso di una lista contenente un solo elemento, la testa sarà l'elemento stesso e la coda la lista vuota.
LISTA TESTA CODA [a]a[][[a, b, c]][a, b, c][]
La suddivisione di una lista in testa e coda è un'operazione molto comune in
Prolog, tanto che esiste un'apposita notazione per rappresentare una lista
che ha una certa testa e una certa coda
[testa|coda].
Introducendo in questa notazione due variabili, ad esempio [X|Y],
è possibile istanziare liste che hanno X come testa e Y come coda.
Le variabili contenute nelle liste vengono istanziate mediante il meccanismo
del
matching
, come mostrato negli esempi seguenti dove si eguagliano
LISTA1 e LISTA2.
LISTA1 LISTA2 istanziazione [X,Y|Z][rossi,verdi]X=rossiY=verdiZ=[][X,Y|Z][prolog,lisp,pascal]X=prologY=lispZ=[pascal][X,Y,Z][prolog,lisp,pascal]X=prologY=lispZ=pascal[studenti,[Y,Z]][X,[mario,giovanni]]X=studentiY=marioZ=giovanni
[X,Y|Z] indica una lista composta da un primo
elemento X, da un secondo elemento Y
e da una coda Z (eventualmente vuota).
[X,Y,Z] indica una lista composta esattamente da tre
elementi X, Y Z.
[X,[Y,Z]] indica una lista composta da un primo
elemento X e da un secondo elemento [Y,Z]
che è a sua volta una lista composta da due elementi.
Provate a vedere come il Prolog risponde alle seguenmti domande:
% file liste/es1.pl /* ?- [genova,milano,roma] = [X|Y]. ?- [10,20,[30,40],cinquanta] = [X|Y]. ?- [a,b,[C,D,[e]]] = [X|Y]. ?- [a]= [X|Y]. ?- [[a, b, c]] = [X|Y].
*/
Consultate nel Database del Prolog i seguenti fatti.
% file liste/es2.pl e_una_lista([questo,e,un,paragrafo,sulle,liste]). e_una_lista([la,vispa,teresa,[avea,tra,l,erbetta]]).
e provate queste domande:
?-e_una_lista([X|Y]). ?-e_una_lista([_|X]). ?-e_una_lista([_,_,_,[X|_]]).
Cercercate di immaginare come il Prolog risponderà. Controllate le vostre risposte con quelle fornite dall'interprete Prolog.
Introduciamo ora il predicato:
membro(X,Y). il quale è vero quando l'elemento associato alla variabile X è contenuto nella lista associata alla variabile Y. Possiamo scrivere il predicato membro tenendo conto che:
membro(X,[X|Y]). membro(X,[_|Y]) :- membro(X,Y).Questa regola presenta un esempio molto classico di ricorsione perchè è definita in termini di se stessa; ovvero, affinchè questa formulazione della regola membro sia vera, occorre che siano vere una o più istanze differenti della regola stessa. Le due regole prima introdotte, sono, insieme, sufficienti a realizzare il concetto di appartenenza. Vediamo alcuni esempi.
%file: liste/es3.pl membro(X,[X|_]). membro(X,[_|Y]):-membro(X,Y).
Come risponderà l'interprete Prolog alle seguenti domande?
?-membro(a,[i,n,f,o,r,m,a,t,i,c,a]). ?-membro(b,[c,o,m,p,u,t,e,r]). ?-membro(c,[m,i,[s,c,e],l,a]).
Vogliamo definire la relazione
conc(L1,L2,L3)
dove L1 e L2 sono due liste e L3
è la loro concatenazione.
Per concatenare due liste possiamo utilizzare le seguenti regole:
conc([],L,L).[X|L1]. Concatenare questa lista con
una seconda lista L2 produce come
risultato una terza lista [X|L3],
dove L3 è la concatenazione di
L1 e L2 (vedi la Fig. 1).
In Prolog:
conc([X|L1],L2,[X|L3]) :- conc(L1,L2,L3).
Dopo aver inserito nel database del Prolog le clausole per conc
Un possibile goal è il seguente:
Vogliamo ora scrivere il predicato
Definite i predicati add, del e insert
Definite il predicato permutazione.
[X|L1]
|X|-------L1----------||-------L2----------|
|X|-------------------L3-------------------|
[X|L3]
Fig 1. Concatenazione di liste.
/* file: liste/es5.pl
/* concatena due liste */
conc([],L,L).
conc([X|L1],L2,[X|L3]) :- conc(L1,L2,L3).
potete usarlo per concatenare due liste:
?- conc([a,b,c],[d,e,f],L).?- conc(X,Y,[a,b,c]).Sottoliste
Utilizzando il predicato conc scrivere un nuovo predicato sublist
sublist(S,L).S è una sottolista di
L.
Suggerimento. La lista S sarà una sottolista della lista
L se esistono
altre due liste, L1 e L3, eventualmente vuote,
tali che concatenando
L1 ed S si ottenga L2 e
concatenando quest'ultima con L3,
si ottenga la lista L. Vedi la Fig. 2.
|-----------------L-----------------|
|-----L1----|-----S-----|-----L3----|
|----------L2-----------|
Fig 2. Sublist. ?- sublist([b,c,d],[a,b,c,d,e]).[a,b,c,d,e].
Assicuratevi che non venga prodotta, fra le varie sottoliste, la
lista vuota.
Inserire e cancellare elementi da una lista
Per aggiungere l'elemento X in testa alla lista L
è sufficiente scrivere [X|L].
Tuttavia possiamo anche scrivere un predicato add(X,L,L1)
che aggiunge l'elemento X in testa alla lista L
fornendo come risultato la lista L1
in questo modo:
add(X,L,[X|L]).delete(X,L,L1).L una qualsiasi occorrenza di
X dando come risultato la lista L1.
Possiamo utilizzare le seguenti regole:
Provate il seguente goal:
X è la testa della lista
cancellare X significa tenere solo la coda della lista.
In Prolog:
del(X,[X|L],L).X è nella coda può essere cancellato
dalla coda mantenendo la stessa testa. In Prolog:
del(X,[T|C],[T|C1]) :- del(X,C,C1). ?- del(b,[a,b,c,b,d,b],L).del può anche essere utilizzato
con il secondo argomento variabile e istanziando il terzo come in:
?- del(z,L,[a,b,c,d,e]).
Possiamo anche scrivere un predicato
insert(X,L,L1)X in una qualsiasi posizione di L (con risultato L1 ) sfruttando del.
%file: liste/es7.pl
% add
add(X,L,[X|L]).
%delete
del(X,[X|L],L).
del(X,[T|C],[T|C1]) :- del(X,C,C1).
%insert
insert(X,L,L1) :- del(X,L1,L).
Cosa risponderà l'interprete Prolog alle seguenti domande?
?- add(x,[y,z,t],L).
?- del(b,[a,b,c,b,d,b],L). % usare l'opzione "all" di query
?- insert(z,[a,b,c,d,e],L). % usare l'opzione "all" di query
Generare tutte le permutazioni degli elementi di una lista
Il predicato
permutazione(L,P).P è una permutazione degli elementi
della lista L.
Con il meccanismo del backtracking si possono generare tutte le permutazioni
P degli elementi della lista L.
Se L=[a,b,c] P=[a,b,c];
P=[b,a,c];
P=[b,c,a];
.........
permutazione([],[]).[X|L], e una permutazione di questa lista può
essere ottenuta inserendo l'elemento X in una
posizione qualsiasi della lista L1 permutazione di
L, come mostrato in Fig. 3.
Per inserire X in L1 possiamo
usare il predicato insert, visto precedentemente. In Prolog:
permutazione([X|L],P):- permutazione(L,L1),insert(X,L1,P).
|X|------------L----------|
|
|
\----\
|
V
|------------L1---------|
(L1 e' una permutazione di L)
Fig. 3 Permutazioni.
%file liste/es8.pl
% permutazioni
permutazione([],[]).
permutazione([X|L],P):- permutazione(L,L1),insert(X,L1,P).
%delete
del(X,[X|L],L).
del(X,[T|C],[T|C1]) :- del(X,C,C1).
%insert
insert(X,L,L1) :- del(X,L1,L).
Scrivete un goal per controllare se [b,c,a] è una permutazione
di [a,b,c].
Scrivete inoltre un goal per ottenere tutte le permutazioni degli elementi
della lista [a,b,c].