Joachim Low
Joachim Low

Reputation: 277

Prolog - add some elements to same list

I have a problem to add elements in a list in Prolog. I use this rule:

add(X, L, [X|L]).

This rule add an element in the Head of the list. If i would add some element to the same list i have this problem:

add(a, L, L1),
add(b, L1,L2),
add(c, L2,L3). 

L3= [a,b,c]

Is there a method to add elements in a list without change the name of variable... L1, L2, L3, but adding they to a single variable L?

Upvotes: 2

Views: 33420

Answers (4)

CapelliC
CapelliC

Reputation: 60004

That's implicitly done by DCG, adding (hidden) difference list arguments to non terminals. But without some more detail about your task it's hard to hint about any sensible usage.

SWI-Prolog has actually some serious capability, via non backtrackable data structures, to perform tasks with 'side effects' propagating thru the solution chain, but I'm not sure if it's opportune to hint you about this feature...

edit an example of updating an RBTree in a failure driven loop:

:- use_module(library(rbtrees)).
:- use_module(library(nb_rbtrees)).

 ordkey :- rb_empty(R),
   forall(member(W, [ls,mkdir,cd,ftp]),
     ( atom_length(W, K),
       (  nb_rb_get_node(R, K, N)
       -> nb_rb_node_value(N, Ws),
          nb_rb_set_node_value(N, [W|Ws])
       ;  nb_rb_insert(R, K, [W])
       )
    )), rb_visit(R, L), writeln(L).

yields

?- ordkey.
[2-[cd,ls],3-[ftp],5-[mkdir]]

Upvotes: 2

NotAUser
NotAUser

Reputation: 1456

The short answer is no: L would have to represent different lists, which is wrong in Prolog.

But you can implement something like this:

add_list([], L, L).
add_list([H|T], L, L1) :- add(H, L2, L1), add_list(T, L, L2).

Sample usage:

?- add_list([1,2,3],X,A).
A = [1, 2, 3|X].

?- add_list([1,2,3],X,A), writeln(A-X), add_list([4,5],Y,X).
[1,2,3|_G1188]-_G1188
X = [4, 5|Y],
A = [1, 2, 3, 4, 5|Y].

?- add_list([1,2,3],X,A), writeln(A-X), add_list([4,5],Y,X),Y=[].
[1,2,3|_G1224]-_G1224
X = [4, 5],
A = [1, 2, 3, 4, 5],
Y = [].

Upvotes: 2

lurker
lurker

Reputation: 58224

Although you can't just add to an existing list, which corresponds to the direct question being asked, there are some classes of problems which can be solved using a predicate whose solutions are individually items you want to collect in a list, and you can collect them with the ISO predicate, findall:

determin_item( ..., X ) :-
    % Logic which determines X
    % Could be complex with multiple Prolog statements and various conditionals

findall( X, determine_item(..., X), List ).

As a trivial example for the case given:

foo(1,a).
foo(1,b).
foo(1,c).
foo(2,e).
foo(3,f).

determine_item( X ) :-
    foo(1, X).  % Trivial example to determine X

findall( X, determine_item(X), List ).

Which will generate:

List = [a,b,c].

Upvotes: 1

Nicholas Carey
Nicholas Carey

Reputation: 74177

The short answer, as noted, is NO.

The longer answer: You can't add items to an existing list (without creating a new list). Nor can you increment a variable like you might in other languages: you can only create a new variable whose value is the source variable incremented by 1. Prolog data types are all immutable. Prolog variables, once bound to a value, cease to be variable. Their binding is undone when execution backtracks through the assignment.

Upvotes: 1

Related Questions