2015-11-24 9 views
5

Si supponga che ho due liste arbitrarie che rappresentano le prime due voci di un 3-posto predicato:Prolog Principiante: Lista Reverse solo una volta

[anna,berta,charlotte],[charles,bob,andy] 

voglio abbinare ogni elemento in un terzo elenco (la terza voce di 3-posto predicato) come segue:

[[anna,andy],[berta,bob],[charlotte,charles]] 

Fondamentalmente gli articoli vengono abbinati in modo sequenziale inverso. Per abbinare gli elementi in modo sequenziale, ho ideato il seguente codice:

match([],[],[]). 
match([A|At],[C|Ct],[[A,C]|Dt]):-match(At,Ct,Dt). 

Ma questo mi avrebbe dato la seguente:

match([anna,berta,charlotte],[charles,bob,andy],X). 
X=[[anna,charles],[berta,bob],[charlotte,andy]] 

Così ho bisogno di invertire il secondo elenco in qualche modo. Finora, ho modificato il codice come segue:

match([],[],[]). 
match([A|At],[C|Ct],[[A,B]|Dt]):-reverse([C|Ct],[B|Bt]),match(At,Bt,Dt). 

Ma questo sarebbe continuamente invertire la seconda lista ad ogni passaggio. Il risultato sarebbe il seguente aspetto:

match([anna,berta,charlotte],[charles,bob,andy],X). 
X=[[anna,andy],[berta,charles],[charlotte,bob]] 

Domanda: Come faccio a invertire la seconda lista solo una volta, in modo che i risultati effettivi corrispondono a quelli desiderati? O il mio approccio è fondamentalmente imperfetto? Sono nuovo di prologo e sono attualmente ostacolato da questo. Qualsiasi aiuto sarebbe apprezzato.

risposta

2

Il trucco per la soluzione di problemi che richiedono di applicare una regola solo una volta è quello di costruire una regola ausiliario che esegue passaggi aggiuntivi prima e/o dopo aver richiamato la regola ricorsiva:

match(A, B, R) :- reverse(B, RevB), match_impl(A, RevB, R). 

match_impl([], [], []). 
match_impl([A|At], [C|Ct], [[A,C]|Dt]) :- match_impl(At, Ct, Dt). 

match_impl/3 è il vostro match/3 regola rinominato per evitare conflitti con la regola "top" match/3 che include un passaggio ausiliario.

3

Esegui esattamente ciò che dici: inverti l'elenco una volta, quindi utilizza l'elenco invertito.

lists_pairs(Ps1, Ps2, Pairs) :- 
    reverse(Ps2, RPs2), 
    pairs_keys_values(Pairs, Ps1, RPs2). 

È possibile controllare il codice sorgente di reverse/2 e pairs_keys_values/3 in qualsiasi libreria decente Prolog per vedere come esso è definito.

Query di esempio e risposta:

?- lists_pairs([anna,berta,charlotte], [charles,bob,andy], Ps). 
Ps = [anna-andy, berta-bob, charlotte-charles]. 

lascio convertire tali coppie alla non sensibile "pair elenco" rappresentazione come esercizio.

+0

s (X) per l'utilizzo di un pulire la rappresentazione dei dati. – repeat

2

Questo è un piccolo follow-up a @mat's answer.

Per agevolare la terminazione in alcuni casi si potrebbe aggiungere un ridondante same_length_as/3 obiettivo in questo modo:

 
lists_pairs(Ps1, Ps2, Pairs) :- 
    same_length_as(Ps1, Ps2, Pairs), 
    reverse(Ps2, RPs2), 
    pairs_keys_values(Pairs, Ps1, RPs2). 

Il predicato ausiliario same_length_as/3 può essere definito in questo modo:

same_length_as([],[],[]). 
same_length_as([_|As],[_|Bs],[_|Cs]) :- 
    same_length_as(As,Bs,Cs). 
+1

'maplist (\ _^_^_^true, Ps1, Ps2, Coppie)' – false