Prolog - add to each lists element - list

I'm learning swi Prolog and I wanted to create predicate that adds +2 for each element.
So I wrote something like this:
addUp([],_).
addUp([H|T],R):-addUp(T,R),is_list(R)->append([H+2],R,R);R=[H+2|[]].
addUp([1,2],X).
But it always returns false. Why?

First an advice: learn to use maplist/3: with that you will write
addUp(Xs, Ys) :- maplist(addUp2, Xs, Ys).
addUp2(X, Y) :- Y is X + 2.
or better, a more reusable snippet...
addUp(Xs, Ys) :- maplist(addUp(2), Xs, Ys).
addUp(N, X, Y) :- Y is X + N.
Anyway, arithmetic in Prolog must be evaluated 'explicitly', and your code must be simplified a lot to work
addUp([], []).
addUp([H|T], [H1|T1]) :- H1 is H+2, addUp(T, T1).

But it always returns false. Why?
Your definition does not always fail:
?- addUp([1],X).
X = [1+2].
So sometimes it succeeds. And it seems that this case is more or less what you wanted. Where else does it succeed? In other programming languages you would have to guess or, heaven forbid, read the program. In Prolog, there is no need for this. Simply find a good query. A good candidate is the most general query:
?- addUp(Xs,Ys).
Xs = [] ...
So your definition succeeds for Xs equal to [], and Ys equal to ... well, equal to anything. Therefore, this answer is too general.
Another goal catches my eye: is_list(R)->append([H+2],R,R). Let's imagine, when this will be true. For R = [] not, nor for R = [_]. In fact, there is no length, where this will be true.
Now, we can start fixing your program. See chac/CapelliC's suggestion.

Related

SWI-Prolog: How to stop the predicate when the list is empty? (predicate included)

course(cmput325).
course(cmput175).
course(cmput201).
course(cmput204).
prerequisite(cmput204, cmput325).
prerequisite(cmput175, cmput201).
prerequisite(cmput175, cmput204).
I need to write a new predicate, which is
can_take(+L,?C).
Definition:
L is a given list of courses that a student has already taken. If C is also given,then the predicate should check whether the student has all the required courses for C. If C is a variable, then with backtracking, the predicate should produce one course at a time that the student can take now. Courses can be in any order, but each course should be generated only once, and you should not return any courses that the student has already taken.
Example:
?- findall(C, can_take([cmput175], C), L).
should return
L = [cmput201, cmput204].
Here is my predicate:
can_take(L,C) :- prerequisite(L,C).
can_take([L|List],C) :- prerequisite(L,C),can_take(List,C).
This predicate didn't return the correct result, and it just returned false. I think it is because I didn't determine the condition when L is empty, however, if I tried to add L \== [] in either of them. It still gave me error...what should I do so that this predicate will stop and give me result?
-------update-------
pre(X,C) :- prerequisite(X,C).
pre(X,C) :- prerequisite(X,Y), pre(Y,C).
pre2(C,L) :- findall(L1,pre(L1,C),L).
required(C,L) :- pre2(C,L1),sort(L1,L).
can_take([],_).
can_take(L,C) :- required(C,L).
can_take([L|List],C) :- prerequisite(L,C),can_take(List,C).
Here is my code test:
?- required(cmput325,L).
L = [cmput175, cmput204].
?- required(cmput204,L).
L = [cmput175].
?- can_take([cmput175],X).
X = cmput201 ;
X = cmput204 ;
?- findall(C, can_take([cmput175], C), L).
L = [cmput201, cmput204].
?- can_take([cmput204],cmput325).
false. (this one is OK)
?- can_take([cmput175,cmput204],cmput325).
true ;
false. (this one is OK)
?- can_take([cmput175],cmput204).
true ;
true ;
false.
the last one is not ok because I don't want it to return two true statements...so what I want is just let it stop when either second or last line returns true. For my assignment, I am not allowed to use cut operator !, is there any other way to do it?
(I will assume that you can take a course a second time, even if you have taken it already. That at least are the rules I know of.)
You can take a course, provided you have taken all required courses already.
There is no direct "all" in Prolog. But you can formulate this differently
You can take a course, provided there is no required course that you have not taken already.
can_take(Takens, Next) :-
course(Next),
iwhen( ground(Takens),
\+ ( prerequisite(Required, Next), \+ member(Required, Takens) ) ).
This uses iwhen/2 to guard against cases where Takens is not fully instantiated.
Note that there is a slight difference to your examples:
?- findall(C, can_take([cmput175], C), L).
L = [cmput175, cmput201, cmput204].
% ^^^^^^^^
Disclaimer
Your problem is inherently non-monotonic: By adding further facts for requirements you are reducing the number of possible courses you may take. As a beginner, rather stick to problems that are monotonic in nature. It is on this side where Prolog really excels.

Remove duplicate from a list but not returning two same results in SWI-Prolog?

duplicate([],[]).
duplicate([A|B],[A|B1]) :- not(member(A,B)), duplicate(B,B1).
duplicate([A|B],List) :- member(A,B), duplicate(B,List).
I wrote this predicate to remove duplicate from the list, but when I test it,
?- duplicate([a,b,c,a,d,c,b,a,e,f],N).
N = [d, c, b, a, e, f] ;
N = [d, c, b, a, e, f] ;
false.
Is there a way to just keep one result only, not two same results? (so it will only return one list).
Also, I am not allowed to use operators that modify the backtracking search, such as the cut operator !, the negation operators not, +, or the if-then-else operator with -> and ;
It would be grateful if someone could help me . :D
The actual reason for receiving more than one answer is the goal member(A,As). It produces multiple answers for duplicates in As.
?- member(a, [a,a]).
true
; true.
There are several ways out.
memberchk/2 or once/1
memberchk/2 is defined as
memberchk(X, Xs) :-
once(member(X, Xs)).
This removes alternate answers. But then, it may remove otherwise valid solutions too. Consider:
?- memberchk(X, [a,b]), b = X.
false.
?- b = X, memberchk(X, [a,b]), b = X.
b = X.
So memberchk/2 is sensitive to the precise instantiation, which makes it a very brittle, impure predicate.
But it has one good point: It sticks to just one answer for
?- memberchk(a, [a,a]).
true.
So what would be ideal is a definition that is both pure and sticking to the first element. Enter
memberd/2
memberd(X, [X|_Ys]).
memberd(X, [Y|Ys]) :-
dif(X, Y),
memberd(X, Ys).
In this definition, the recursive rule is only of relevance if the list element is different. Thus this rule will never apply to memberd(a, [a,a,a]).
Another problem in your definition is not(member(A,B)) which only behaves as intended, if A and B are sufficiently instantiated. Your definition fails for:
duplicate([a,X],[a,b]). although there is a solution: X = b.
Rather replace it by non_member/2.
Alternatively, in case you are interested in the most efficient solution, consider library(reif) available
for
SICStus and
SWI which leads to:
list_nub([], []).
list_nub([X|Xs], Ys0) :-
if_(memberd_t(X, Xs), Ys0 = Ys1, Ys0 = [X|Ys1]),
list_nub(Xs, Ys1).
Here's one way to remove all duplicates, not the most efficient but I think it's quite easy to understand the intention.
rm_duplicates(In, Out) :-
exclude(has_duplicate(In), In, Out).
has_duplicate(List, Case) :-
dif(I, J),
nth0(I, List, Case),
nth0(J, List, Case).
If you mean to make a list into a set:
list_to_set(List, Set).
It's documented: list_to_set/2

A prolog predicate checks if an element occurs at least twice in a list

twice(X,[X|Y]):-
member(X,[Y]).
twice(X,[Y|Z]):-
twice(X,[Z]),
X\=Y.
I can't find any syntax error,but the execution fails every time.
You've got a misconception about the list structure. The list [H|T] has head element H and tail list T. So T is itself a list. If you put [T] then that's a list of only one element, that element being the list T.
Also, in your second predicate clause, you don't need the X argument or to check for X \= Y since it's not really relevant if you're checking for at least twice.
Thus, your solution changes a little to:
twice(X, [X|T]) :-
member(X, T).
twice(X, [_|T]) :-
twice(X, T).
Which says that X occurs twice in [X|T] if X is a member of T or X occurs twice in [_|T] if X occurs twice in T.
I like your intent, but cannot reproduce what you claim: that this predicate fails all the time. In fact, it loops! And here is the fragment why failure-slice:
twice(X,[X|Y]):- false,
member(X,[Y]).
twice(X,[Y|Z]):-
twice(X,[Z]), false,
X\=Y
?- twice(a,[a,a]).
Because this fragment loops, also your original program loops. Lurker has already shown you what is wrong. Here are some alternate formulations:
twice(X, Xs) :-
phrase( ( ..., [X], ..., [X], ... ), Xs).
... --> [] | [_], ... .
Nevertheless, this program has a big flaw:
?- twice(a,[a,a,a]).
true
; true
; true
; false.
Thrice the very same answer. One time is more than enough!
The ambiguity comes from the ...-non-terminal which means just any sequence. There are three ways how that matches the list [a,a,a]:
[ a, a, a ]
...,[X],...,[X], ...
...,[X], ..., [X],...
..., [X],...,[X],...
To remove the ambiguity we need to replace the ... by something more specific. In stead of anything, the sequence should match anything but X. In this way only the first match remains.
twice(X, Xs) :-
phrase( ( all(dif(X)), [X], all(dif(X)), [X], ... ), Xs).
all(_) --> [].
all(P_1) -->
[E],
{call(P_1,E)},
all(P_1).
?- twice(a,[a,a,a]).
true
; false.
That's much better. But is it the bestest? Here is a further improvement using library(reif) for SICStus|SWI.
:- use_module(library(reif)).
twice(C, [X|Xs]) :-
if_(C = X, memberd(X, Xs), twice(C, Xs) ).
memberd(C, [X|Xs]) :-
if_(C = X, true, memberd(C, Xs) ).
?- twice(a,[a,a,a]).
true.
twicee(X,[X|Y]):- member(X,Y).
twicee(X,[_|Y]):-twicee(X,Y), X\=Y.
Working code for me, check if there are two elements in a list. For example:
twicee(X,[a,a,b,b,c,d]).
X = a.
X= b.
twicee(c,[a,a,b,b,d]).
FALSE.

Element handling issue in Prolog, but not in a regular list?

I'm trying to write an element handling function in Prolog. It's almost the same as the prolog predicate member/2 but it must do the job in a different way. For being specific; I must say the member/2 predicate function is this:
member(X, [X|_]).
member(X, [_|Tail]) :-
member(X,Tail).
When you give a query for example: member(X, [1,2,3]).
It gives you X = 1; X = 2; X = 3; in this order for all redo's. I want an element function almost the same. I want the same result with the member function when I give a query like this:
element(X, (1,2,3)).
The difference is just parenthesis instead of bracekts like these : []
In order to do this I tried that:
element(X, (X,_)).
element(X, (_,Tail)) :-
element(X,Tail).
Which is exactly the same as member/2 predicate function implementation. But this doesn't work because it doesn't giving the last element which is X=3.
So I added one more fact that is:
element(X, X).
But this doesn't work either because (obviously) it is giving unnecessary answer with real elements like these:
X=(1,2,3)
X=(2,3)
How can I handle this?
Seems that a cut can solve your problem:
element(X, (X, _)).
element(X, (_, Tail)) :-
!, element(X, Tail).
element(X, X).
test:
?- element(X, (1,2,3)).
X = 1 ;
X = 2 ;
X = 3.
?- element(2, (1,2,3,2)).
true ;
true.
Terms like (1,2,3) in Prolog have commas as their primary functor. Probably you want to use operator univ, denoted by infix =.., or its close relations functor/3 and arg/3 to pick apart these tuples.

flatten list by replacing comma with plus operator inside a list in prolog

I am working on a scenario in Prolog (eclipse) wherein I need a list structure to be reformatted.
I have a list of the form:
MyList = [a,b,c].
I was trying to see if I can flatten the list to a single element with all the commas replaced with the + operator.
So my result list would look like:
ResultList = [a+b+c]
which is a single element list. The length of the initial list is arbitrary.
I know prolog is not suited for such operations, but can this be done?
here it is, in standard Prolog. I think there should be no difference with Eclipse:
list_to_op([X,Y|T], [R]) :-
list_to_op(T, X+Y, R).
edit: bug noted by false
list_to_op([X], [X]).
list_to_op([X], R, R+X).
list_to_op([X|T], R, Q) :-
list_to_op(T, R+X, Q).
test:
?- list_to_op([a,b,c],X).
X = [a+b+c] .
The accumulator is required to give the appropriate associativity: the simpler and more intuitive definition
list_to_op1([X], X).
list_to_op1([X|R], X+T) :-
list_to_op1(R, T).
gives
?- list_to_op1([a,b,c],X).
X = a+ (b+c) .
If evaluation order is important, use list_to_op.
edit:
there is a bug: list_to_op([a,b],X) fails.
here the correction, as often happens, it's a simplification:
list_to_op([], R, R).
list_to_op([X|T], R, Q) :-
list_to_op(T, R+X, Q).
This may help
flatten_list(A,[B]) :- flatten_list_inner(A,B).
flatten_list_inner([A],A).
flatten_list_inner([H|T],H+Y) :- flatten_list_inner(T,Y).
The output is slightly different from what you wanted. It is currently [a + (b + c)]
How about this non-recursive version..
list_to_op(L, Res) :-
concat_atom(L, '+', Atom),
Res = [Atom].
?- list_to_op([a,b,c], X).
X = ['a+b+c'].
Edit: This works in Swi-prolog.. not sure about Eclipse.