Related
I am trying to check whether the interaction provided is the correct intersection of two lists. Example query list:
?- intersectionL([1,2,3,4],[1,3,5,6],[1,3]).
/* expected output: true. */
?- intersectionL([1,2,3,4],[1,3,5,6],X).
/* expected output: X = [1,3]. */
?- intersectionL([1,2,3],[4,3],[3]).
/* expected output: true. */
I have written a function to calculate the intersection of two lists (intersectionL). From there I want to verify whether the third argument given is the same as the intersection I found (intersectionHelper).
intersectHelper([], []).
intersectHelper([H1|T1], [H2|T2]):-
H1 = H2, intersectHelper(T1, T2).
intersectionL([], X, []).
intersectionL([H1|T1], L2, [H1|Res]):-
member(H1, L2), intersectionL(T1, L2, Res).
intersectionL([X|T1], L2, Res):-
intersectionL(T1, L2, Res).
I am having two problems: Firstly, how do I use intersectionHelper within intersectionL. Secondly, how do I output the list of intersections if no list is provided (like in query 2 above).
Edit: I was able to solve it for anyone else interested. I do not require intersectionHelper.
intersectionL([], X, []).
intersectionL([H1|T1], L2, [H1|Res]):-
member(H1, L2), intersectionL(T1, L2, Res).
intersectionL([X|T1], L2, Res):-
intersectionL(T1, L2, Res).
Not an answer but there I note that there is a RED CUT missing in intersectionL/3:
For example, computing the intersection of [1,2,3] and [1,4,5] gives two solutions, only one of which is desired:
?- intersectionL([1,2,3],[1,4,5],L).
L = [1] ; % desired
L = []. % not desired
We need to add a guard condition in the second clause:
intersectionL([], X, []).
intersectionL([H1|T1], L2, [H1|Res]):-
member(H1, L2), intersectionL(T1, L2, Res).
intersectionL([X|T1], L2, Res):-
\+member(H1, L2), intersectionL(T1, L2, Res).
or use a "red cut" to tell Prolog to not try the third clause if the second succeeded (this is ugly):
intersectionL([], X, []).
intersectionL([H1|T1], L2, [H1|Res]):-
member(H1, L2),!,intersectionL(T1, L2, Res).
intersectionL([X|T1], L2, Res):-
intersectionL(T1, L2, Res).
Best is to have an explicit guard with a green cut to shed any choicepoints that are of no use, while still staying declarative:
intersectionL([], _, []).
intersectionL([H1|T1], L2, [H1|Res]):-
member(H1, L2),!,intersectionL(T1, L2, Res).
intersectionL([H1|T1], L2, Res):-
\+member(H1, L2),!,intersectionL(T1, L2, Res).
Now it works, one solution only.
?- intersectionL([1,2,3],[1,4,5],L).
L = [1].
Second day I am trying to make something like this work:
?- sm([1,2,3,4], [3,4,5,6], X).
X = [4,6,8,10].
I have something like this for now:
sm([], []).
sm([Head1|Rest1], [Head2|Rest2], R) :-
ResultElem is Head1 + Head2,
append([ResultElem], R, R1),
sm(Rest1, Rest2, R1).
I get only:
Singleton variables: [X]
false
Why does it not working and how this can finally be overcome?
The problem is that your recursive sm/3 does not have a matching base, because you wrote sm/2 by mistake:
sm([], [], []). /* You forgot the third pair of [] brackets */
As far as the recursive clause goes, it is easier to put the result in the header of the rule, and it lets you avoid using append:
sm([Head1|Rest1], [Head2|Rest2], [ResultElem|R]) :-
ResultElem is Head1 + Head2,
sm(Rest1, Rest2, R).
you can use maplist :
add(X,Y,Z) :-
Z is X+Y.
my_sum(L1, L2, L) :-
maplist(add, L1,L2,L).
With SWI-Prolog and module lambda, you can write
:- use_module(library(lambda)).
my_sum(L1,L2,L) :-
maplist(\X^Y^Z^(Z is X+Y), L1, L2, L).
Finally, with module clpfd, you can have:
:- use_module(library(lambda)).
:- use_module(library(clpfd)).
my_sum(L1,L2,L) :-
maplist(\X^Y^Z^(Z #= X+Y), L1, L2, L).
and we have :
?- my_sum([1,A, 9] ,[B,5,6], [5,7,C]).
A = 2,
B = 4,
C = 15.
This is my code
removevowels(L1, L2) :-
removevowels(L1, L2, []).
removevowels([], [], _).
removevowels([X|L1], [X|L2], Aux) :-
consonant(X),
not(member(X, Aux)),
removevowels(L1, L2, [X|Aux]).
removevowels([X|L1], L2, Aux) :-
not(consonant(X)),
removevowels(L1, L2, Aux).
If i run this:
?- removevowels([a,m,m,n], X).
It should print
X = [m, n]
but it's giving false and if i run this
?- removevowels([a,m,n], X).
X = [m,n]
It's alright when it doesn't have repeated elements.
Auxiliar predicates used:
member(X, [X|_]).
member(X, [_|Tail]) :-
member(X, Tail).
consonant(b)
consonant(c), etcetc ....
What's wrong in my code?
The best is to replace not/1 by the ISO (\+)/1 first.
For debugging, the first thing you would do is to minimize the problem. E.g., the query
?- removevowels([m,m],X).
is just as bad. But much smaller. So what are your rules for consonants? There is a single rule:
removevowels([X|L1], [X|L2], Aux) :-
consonant(X),
\+member(X, Aux),
removevowels(L1, L2, [X|Aux]).
So consonants have to occur only once, the next occurrence makes this fail already.
Should you still not be sure why the query fails, you might also want to generalize the query. In stead of seeing that removevowels([m,m],X) fails, you might ask
?- removevowels([m,Y],X).
which means: Is there any Y such that there is a solution. However, this method only works, if your program is "relational". In your case the last rule, however prevents this:
removevowels([X|L1], L2, Aux) :-
\+consonant(X),
removevowels(L1, L2, Aux).
It will never succeed with X being an uninstantiated variable. I'd rather use instead:
removevowels([X|L1], L2, Aux) :-
vowel(X),
removevowels(L1, L2, Aux).
Back to consonants:
What you are missing is either a separate rule for consonants that are already present, or some "defaulty" if-then-else.
Further, this extra checking might not be the most effective way to handle this. Maybe just extract the vowels first, and then sort/2 them.
in second clause, there are two 2 conditions in join, while the last clause has only one. I would commit the good case with a cut, and let the last clause only act as a trusted skip clause:
removevowels([], [], _).
removevowels([X|L1], [X|L2], Aux) :-
consonant(X),
not(member(X, Aux)),
!, removevowels(L1, L2, [X|Aux]).
removevowels([_X|L1], L2, Aux) :-
removevowels(L1, L2, Aux).
using if/then/else construct for the last 2 clauses, we avoid the problem noted by false:
removevowels([], [], _).
removevowels([X|L1], R, Aux) :-
( consonant(X),
not(member(X, Aux))
-> R=[X|L2],
removevowels(L1, L2, [X|Aux])
; removevowels(L1, R, Aux)
).
I've written the following code in prolog:
contains(L1, []).
contains(L1, [X | T2]) :- member(X, L1), contains(L1, T2).
minus(L, [], L).
minus(L1, L2, L3) :- contains(L1, L3), nomembers(L3, L2).
nomembers(L1, []).
nomembers(L1, [X | T2]) :- not(member(X, L1)), nomembers(L1, T2).
contains(L1, L2) returns true if all of the members in L2 appear in L1. (contains([1,2],[1,1,1]) is true).
minus(L1, L2, L3) returns true if L3=L1\L2, meaning L3 consists of members of L1 but not of L2.
When I ask minus([1,2,3,4],[2,1],L), I get the answer that L=[], although logically it should be L=[3,4]. Does someone know why?
Above comment of mbratch is very helpful.
Notice, that your current minus(L1, L2, L3) definition is: All members of L3 are in L1 and no member from L3 is in L2.
Prolog is giving you good answer with L3 = [], it fits for definition I wrote above.
EDIT: Below code should do what you want, but currently I don't have prolog on my computer, so I can't test it.
remove(X, [X|T], T) :- !.
remove(X, [H|T], [H|T2]) :- remove(X, T, T2).
minus(L1,[],L1).
minus(L1,[H|T2],T3) :- member(H, L1), !, remove(H,L1,L4), minus(L4, T2, T3).
minus(L1,[H|T2],[H|T3]) :- minus(L1, T2, T3).
remove(X,LA,LB) which says: LB is LA without it first occurrence of X, so it's just removing element from the list.
I my have code:
locdiff([A|T], [A|_], T).
locdiff([H|T], L2, [H|T2]) :-
locdiff(T, L2, T2).
and when i test it with locdiff([(a,1), (b,2), (b,3), (c,3), (c,4)], [(b,_)], L3), it only finds and removes one of the [(b,_)] which is (b,2). I need it to find and remove both (b,2) and (b,3) or what ever the [(b,_)] contains. can anyone help me with what i have missed?
there is a technical complication that's worth to note if you follow larsman' hint, that I would implement straight in this way
locdiff([], _, []).
locdiff([A|T], [A|_], R) :-
!, locdiff(T, [A|_], R).
locdiff([H|T], L2, [H|T2]) :-
locdiff(T, L2, T2).
with this
?- locdiff([(a,1), (b,2), (b,3), (c,3), (c,4)], [(b,_)], L3).
L3 = [ (a, 1), (b, 3), (c, 3), (c, 4)].
you can see that the first instance is removed, and the last. That's because the first match binds the anonymous variable, and then forbids following matchings, except the last (b,_)
Then a completed procedure would read
locdiff([], _, []).
locdiff([H|T], [A|_], R) :-
\+ \+ H = A, % double negation allows matching without binding
!, locdiff(T, [A|_], R).
locdiff([H|T], L2, [H|T2]) :-
locdiff(T, L2, T2).
now the outcome is what you are requiring.
Alternatively, you need to be more precise in pattern matching, avoiding undue binding
locdiff([], _, []).
locdiff([(A,_)|T], [(A,_)|_], R) :-
!, locdiff(T, [(A,_)|_], R).
locdiff([H|T], L2, [H|T2]) :-
locdiff(T, L2, T2).
?- locdiff([(a,1), (b,2), (b,3), (c,3), (c,4)], [(b,_)], L3).
L3 = [ (a, 1), (c, 3), (c, 4)].
Please note that some library has specific functionality, like exclude/3 in SWI-Prolog, but still you need attention to avoid bindings:
eq([(E,_)|_], (E,_)).
locdiff(L, E, R) :-
exclude(eq(E), L, R).
May be you need something loke that :
locdiff([], _, []).
locdiff([(b,_)|T], [(b,_)], T1) :-
!, locdiff(T, [(b,_)], T1).
locdiff([H|T], L2, [H|T2]) :-
locdiff(T, L2, T2).
But why do you write [A| _] if there is only one element in the list ?
[EDIT] I forgot the ! in the second rule