Adding to a list of lists in Prolog

2019-07-29 17:17发布

问题:

I am currently attempting to write a Prolog program which will add a given character to the end of a list. The list's I want to append are elements within a list. This is what I currently have.

extends(X, [], []).
extends(X, [[Head]|Lists], Y):-
    append([X], [Head], Y),
    extends(X, Lists, [Y]).

Here I'm attempting to concatenate X and Head, storing it in Y. However I want Y to be a list of lists, so when it repeats the process again the next concatenation will be stored also in Y. So at the end of the program Y would store the results of all the concatenations. I would want the result to look like as follows.

?- extends(a, [[b,c], [d,e,f], [x,y,z]], Y).
Y = [[b,c,a], [d,e,f,a], [x,y,z,a]].

Could anyone help me out with this?

回答1:

You want to apply some operation to corresponding elements of two lists. That operation talks about lists itself. It's easy to get confused with the nested levels of lists, so let's try not to think in those terms. Instead, define first a predicate that does the extension of one list:

element_list_extended(Element, List, Extended) :-
    append(List, [Element], Extended).

This behaves as follows, using cases from your example:

?- element_list_extended(a, [b, c], Extended).
Extended = [b, c, a].

?- element_list_extended(a, List, [x, y, z, a]).
List = [x, y, z] ;
false.

Looks good so far. All we need to do is to apply this operation to corresponding elements of two lists:

extends(_Element, [], []).
extends(Element, [Xs | Xss], [Ys | Yss]) :-
    element_list_extended(Element, Xs, Ys),
    extends(Element, Xss, Yss).

And this works:

?- extends(a, [[b,c], [d,e,f], [x,y,z]], Y).
Y = [[b, c, a], [d, e, f, a], [x, y, z, a]] ;
false.

The key to making it work was to decompose the problem into two parts and to solve those simpler parts separately.

Now, if we like, since the definition of element_list_extended/3 is a single clause containing a single goal, we might decide to do without it and inline its definition into extends/3:

extends(_Element, [], []).
extends(Element, [Xs | Xss], [Ys | Yss]) :-
    append(Xs, [Element], Ys),
    extends(Element, Xss, Yss).

As you can see, you were quite close! You just had some superfluous brackets because you got confused about list nesting. That's precisely where decomposing the problem helps.

(As the other answer said, SWI-Prolog has some useful libraries that allow you to express even this in even shorter code.)



回答2:

extends(PostFix, ListIn, ListOut) :-
    maplist({PostFix}/[In,Out]>>append(In,[PostFix],Out),ListIn, ListOut).

This is using library(yall) a maplist/3 and append/3.



标签: prolog