Prolog - copy a piece of list

2020-04-11 08:21发布

问题:

I need to duplicate list in prolog.

I have list:

L = [a(string1,value1),a(string2,value2),a(string3,value3),a(string4,value4)].

Output will be: L = [string1, string2, string3, string4].

How can I do this?

I can copy whole list by code:

copy([],[]).
copy([H|L1],[H|L2]) :- copy(L1,L2).

I have tried something like:

copy2([],[]).
copy2([H|L1],[K|L2]) :- member(f(K,_),H), copy2(L1,L2). 

But it does not work properly.

But I need only strings from my original list. Can anyone help?

回答1:

pattern matching is used to decompose arguments: you can do

copy([],[]).
copy([a(H,_)|L1],[H|L2]) :- copy(L1,L2).


回答2:

It is uncommon to use a structure a/2 for this purpose. More frequently, (-)/2 is used for this. Key-Value is called a (key-value) pair.

Also the name itself is not very self-revealing. This is no copy at all. Instead, start with a name for the first argument, and then a name for the second. Lets try: list_list/2. The name is a bit too general, so maybe apairs_keys/2.

?- apairs_keys([a(string1,value1),a(string2,value2)], [string1, string2]).

Here are some definitions for that:

apairs_keys([], []).
apairs_keys([a(K,_)|As], [K|Ks]) :-
   apairs_keys(As, Ks).

Or, rather using maplist:

apair_key(a(K,_),K).

?- maplist(apair_key, As, Ks).

Or, using lambdas:

?- maplist(\a(K,_)^K^true, As, Ks).

Declarative debugging techniques

Maybe you also want to understand how you can quite rapidly localize the error in your original program. For this purpose, start with the problematic program and query:

copy2([],[]).
copy2([H|L1],[K|L2]) :-
   member(f(K,_),H),
   copy2(L1,L2).

| ?- copy2([a(string1,value1),a(string2,value2),a(string3,value3),a(string4,value4)], [string1, string2, string3, string4]).
no

Now, generalize the query. That is, replace terms by fresh new variables:

| ?- copy2([a(string1,value1),a(string2,value2),a(string3,value3),a(string4,value4)], [A, B, C, D]).
no
| ?- copy2([a(string1,value1),a(string2,value2),a(string3,value3),a(string4,value4)], L).
no
| ?- copy2([a(string1,value1),B,C,D], L).
no
| ?- copy2([a(string1,value1)|J], L).
no
| ?- copy2([a(S,V)|J], L).
no
| ?- copy2([A|J], L).
A = [f(_A,_B)|_C],
L = [_A|_D] ? 
yes

So we hit bottom... It seems Prolog does not like a term a/2 as first argument.

Now, add

:- op(950,fx, *).

*_.

to your program. It is kind of a simplistic debugger. And generalize the program:

    copy2([],[]).
    copy2([H|L1],[K|L2]) :-
       member(f(K,_),H),
       * copy2(L1,L2).

Member only succeeds with H being of the form [_|_]. But we expect it to be a(_,_).



标签: list copy prolog