Related
I'm trying to return true if either of the two rules on opposite sides of an or operator succeed in Prolog. It only works if what's on the left side of the or operator is found to be true.
It seems like my code should work according to http://www.cse.unsw.edu.au/~billw/dictionaries/prolog/or.html.
Case2 works when case1 is commented out, so it should be returning true, but because it is on the right side of the operator, it isn't. (?)
For clarity, the parameters mean Person1, Person2, TypeOfCousinsTheyAre, DegreesRemovedTheyAre. I am trying to write rules that determine whether two people are first-cousins-once-removed.
Here is the line that uses the or operator which won't return true if the right side is true:
cousins(A, B, 1, 1) :- ( cousinsCase1(A, B, 1, 1) ; cousinsCase2(A, B, 1, 1) ).
Other things I have tried:
(1) Omitting the or operator and writing two identical functions, but whenever they are called and the top one fails, my program crashes.
cousins(A, B, 1, 1) :- var(FirstCousin),
cousin(A, FirstCousin, 1, 0),
parent(FirstCousin, B),
A \= B.
cousins(A, B, 1, 1) :- var(P1),
parent(P1, A),
cousin(P1, B, 1, 0),
A \= B,
A \= P1,
B \= P1.
(2) I have also tried an if-statement to call the other function if the first one fails, but it crashes if the first case fails again.
cousins(A, B, 1, 1) :- cousinsCase1(A, B, 1, 1) -> true ; cousinsCase2(A, B, 1, 1)).
Is there a different way to call the other rule if the first one fails?
EDIT
To take the advice given, here is more of the code:
Facts:
parent(gggm, ggm).
parent(ggm, gm).
parent(gm, m).
parent(m, self).
parent(self, d).
parent(d, gd).
parent(gggm, gga).
parent(gga, c12a).
parent(c12a, c21a).
parent(c21a, c3).
parent(ggm, ga)
parent(ga, c11a).
parent(c11a, c2).
parent(gm, a).
parent(a, c1).
parent(m, s).
parent(s, n).
parent(n, gn).
parent(c1, c11b).
parent(c11b, c12b).
parent(c2, c21b).
parent(c21b, c22).
parent(c3, c31).
parent(c31, c32).
Other rules I have written in order to get the above ones to work:
% Sibling Rule
sibling(A, B) :- parent(P, A), parent(P, B), A \= B.
% First-cousin Rule:
cousin(A, B, 1, 0) :- sibling(P1, P2), parent(P1, A), parent(P2, B).
% Second-cousin Rule:
cousin(A, B, 2, 0) :- parent(P1, A),
parent(P2, B),
parent(PP1, P1), % your grandparent
parent(PP2, P2), % your grand-aunt/uncle
sibling(PP1, PP2). % they're siblings
% 3rd-cousin and more Rule
cousin(A, B, M, 0) :- ReducedM = M - 1,
cousin(A, B, ReducedM, 0).
Calls to the above rules: Sidenote: Both calls do work but the problem is getting them both to work without commenting out the other rule:
cousins(self, c11b, 1, 1).
This call corresponds to the first "1st-cousin, once-removed" case and the case returns the correct answer of true if the other case is commented out.
cousins(self, c11a, 1, 1).
This call corresponds to the second "1st-cousin, once-removed" case and the case returns the correct answer of true if the other case is commented out.
This is a comment in an answer because it will not format correctly in a comment.
What most beginners to Prolog don't realize early enough is that Prolog is based on logic (that they realize) and the three basics operators of logic and, or and not are operators in Prolog, namely (, ; \+). It is not realizing those operators for what they really are.
Starting with not which in Prolog use to be not/1 but is now commonly (\+)/1.
?- \+ false.
true.
?- \+ true.
false.
or using the older not/1 which you can use but is like speaking in a Shakespearean play because it is no longer done this way. I am including this here because many older examples still have it in the examples this way.
?- not(true).
false.
?- not(false).
true.
Next is and which in Prolog is ,/2.
The reason many new Prolog users don't see this as logical and is that a , in many other programming languages is seen as a statement separator (Ref) and acting much like a , in an English sentence. The entire problem with understating , in programming is that it is really an operator and is used for so many things that programmers don't even realize that it should almost always be thought of as an operator but with many different meanings, (operator overloading). Also because , is used as a statement separator, the statements are typically put on separate lines and some programmers even think that a comma (,) is just a statement end like a period (.) is a line end in a sentence; that is not the way to think of these single character operators. They are operators and need to be seen and comprehended as such.
So now that you know where and how your ideas that cause you problems are coming from, the next time you see a comma , or a period . in a programming language really take time to think about what it means.
?- true,true.
true.
?- true,false.
false.
?- false,true.
false.
?- false,false.
false.
Finally logical or which in Prolog is ;/2 or in DCGs will appear as |/2. The use of |/2 in DCGs is the same as | in BNF.
?- true;true.
true ;
true.
?- true;false.
true ;
false.
?- false;true.
true.
?- false;false.
false.
The interesting thing to note about the results of using or (;) in Prolog is that it will they will return when true as many times as one of the propositions is true and false only when all of the propositions are false. (Not sure if proposition is the correct word to use here). e.g.
?- false;false;false.
false.
?- false;false;true.
true.
?- true;false;true.
true ;
true.
?- true;true;true.
true ;
true ;
true.
In case you didn't heed my warning about thinking about the operators when you see them, how many of you looked at
?- true,true.
true.
and did not think that would commonly be written in source code as
true,
true.
with the , looking like a statement end. , is not a statement end, it is the logical and operator. So do yourself a favor and be very critical of even a single , as it has a specific meaning in programming.
A reverse way to get this idea across is to use the addition operator (+) like a statement end operator which it is not but to someone new to math could be mistakenly taken to be that as seen in this reformatting of a simple math expression.
A =
1 +
2 +
3
That is not how one is use to seeing a simple math expression, but in the same way how some programmers are looking at the use of the , operator.
Over the years one thing I have seen that divides programmers who easily get this from the programmers who struggle with this all their careers are those that do well in a parsing class easily get this because they have to parse the syntax down to the tokens such as ,, then convert that into the semantics of the language.
For more details see section 1.2. Control on page 23 of this paper.
EDIT
You really need to use test cases. Here are two to get you started.
This is done using SWI-Prolog
:- begin_tests(family_relationship).
sibling_test_case_generator(ggm ,gga ).
sibling_test_case_generator(gga ,ggm ).
sibling_test_case_generator(gm ,ga ).
sibling_test_case_generator(ga ,gm ).
sibling_test_case_generator(m ,a ).
sibling_test_case_generator(a ,m ).
sibling_test_case_generator(self,s ).
sibling_test_case_generator(s ,self).
test(01,[forall(sibling_test_case_generator(Person,Sibling))]) :-
sibling(Person,Sibling).
cousin_1_0_test_case_generator(gm ,c12a).
cousin_1_0_test_case_generator(ga ,c12a).
cousin_1_0_test_case_generator(m ,c11a).
cousin_1_0_test_case_generator(a ,c11a).
cousin_1_0_test_case_generator(self,c1 ).
cousin_1_0_test_case_generator(s ,c1 ).
cousin_1_0_test_case_generator(d ,n ).
cousin_1_0_test_case_generator(c12a,gm ).
cousin_1_0_test_case_generator(c12a,ga ).
cousin_1_0_test_case_generator(c11a,m ).
cousin_1_0_test_case_generator(c11a,a ).
cousin_1_0_test_case_generator(c1 ,self).
cousin_1_0_test_case_generator(c1 ,s ).
cousin_1_0_test_case_generator(n ,d ).
test(02,[nondet,forall(cousin_1_0_test_case_generator(Person,Cousin))]) :-
cousin(Person, Cousin, 1, 0).
:- end_tests(family_relationship).
EDIT
By !Original:J DiVector: Matt Leidholm (LinkTiger) - Own work based on: Cousin tree.png, Public Domain, Link
This is an answer.
Using this code based on what you gave in the question and a few changes as noted below this code works. Since you did not give test cases I am not sure if the answers are what you expect or need.
parent(gggm, ggm).
parent(ggm, gm).
parent(gm, m).
parent(m, self).
parent(self, d).
parent(d, gd).
parent(gggm, gga).
parent(gga, c12a).
parent(c12a, c21a).
parent(c21a, c3).
parent(ggm, ga).
parent(ga, c11a).
parent(c11a, c2).
parent(gm, a).
parent(a, c1).
parent(m, s).
parent(s, n).
parent(n, gn).
parent(c1, c11b).
parent(c11b, c12b).
parent(c2, c21b).
parent(c21b, c22).
parent(c3, c31).
parent(c31, c32).
% Sibling Rule
sibling(A, B) :-
parent(P, A),
parent(P, B),
A \= B.
% First-cousin Rule:
cousin(A, B, 1, 0) :-
sibling(P1, P2),
parent(P1, A),
parent(P2, B).
% Second-cousin Rule:
cousin(A, B, 2, 0) :-
parent(P1, A),
parent(P2, B),
parent(PP1, P1), % your grandparent
parent(PP2, P2), % your grand-aunt/uncle
sibling(PP1, PP2). % they're siblings
% 3rd-cousin and more Rule
cousin(A, B, M, 0) :-
% ReducedM = M - 1,
ReducedM is M - 1,
ReducedM > 0,
cousin(A, B, ReducedM, 0).
cousinsCase1(A, B, 1, 1) :-
% var(FirstCousin),
cousin(A, FirstCousin, 1, 0),
parent(FirstCousin, B),
A \= B.
cousinsCase2(A, B, 1, 1) :-
% var(P1),
parent(P1, A),
cousin(P1, B, 1, 0),
A \= B,
A \= P1,
B \= P1.
cousins(A, B, 1, 1) :-
(
cousinsCase1(A, B, 1, 1)
;
cousinsCase2(A, B, 1, 1)
).
The first change was as Paulo noted and the checks for var/2 were commented out.
The next change was to change = to is.
The third change to stop infinite looping was to add ReducedM > 0,.
This query now runs.
?- cousins(Person,Cousin,1,1).
Person = gm,
Cousin = c21a ;
Person = ga,
Cousin = c21a ;
Person = m,
Cousin = c2 ;
Person = a,
Cousin = c2 ;
Person = self,
Cousin = c11b ;
Person = s,
Cousin = c11b ;
Person = d,
Cousin = gn ;
Person = c12a,
Cousin = m ;
Person = c12a,
Cousin = a ;
Person = c12a,
Cousin = c11a ;
Person = c11a,
Cousin = self ;
Person = c11a,
Cousin = s ;
Person = c11a,
Cousin = c1 ;
Person = c1,
Cousin = d ;
Person = c1,
Cousin = n ;
Person = n,
Cousin = gd ;
Person = m,
Cousin = c12a ;
Person = self,
Cousin = c11a ;
Person = d,
Cousin = c1 ;
Person = gd,
Cousin = n ;
Person = c21a,
Cousin = gm ;
Person = c21a,
Cousin = ga ;
Person = c11a,
Cousin = c12a ;
Person = c2,
Cousin = m ;
Person = c2,
Cousin = a ;
Person = a,
Cousin = c12a ;
Person = c1,
Cousin = c11a ;
Person = s,
Cousin = c11a ;
Person = n,
Cousin = c1 ;
Person = gn,
Cousin = d ;
Person = c11b,
Cousin = self ;
Person = c11b,
Cousin = s ;
false.
I am trying to break a word into different syllables in Prolog according to 2 different rules ..
rule 1: vowel-consonant-vowel (break word after second vowel)
rule 2: vowel-consonant-consonant-vowel (break word between the 2
consonant) , for example, calculator = cal-cula-tor ..
I already have the following code in Prolog, however, it only analyzes the first 3 or 4 letters of the word ..
I need it to process and analyze the entire word.
vowel(a).
vowel(e).
vowel(i).
vowel(o).
vowel(u).
consonant(L):- not(vowel(L)).
syllable(W, S, RW):-
atom_chars(W, [V1, C, V2|Tail]),
vowel(V1),
consonant(C),
vowel(V2),
!,
atomic_list_concat([V1, C, V2], S),
atomic_list_concat(Tail, RW).
syllable(W, S, RW):-
atom_chars(W, [V1, C, C2, V2|Tail]),
vowel(V1),
consonant(C),
consonant(C2),
vowel(V2),
!,
atomic_list_concat([V1, C, C2, V2], S),
atomic_list_concat(Tail, RW).
syllable(W, W, _).
break(W, B):-
syllable(W, B, ''), !.
break(W, B):-
syllable(W, S, RW),
break(RW, B2),
atomic_list_concat([S, '-', B2], B).
First, a setting that makes it much more convenient to specify lists of characters, and which I recommend you use in your code if you process text a lot:
:- set_prolog_flag(double_quotes, chars).
Second, the data, represented in such a way that the definitions can be used in all directions:
vowel(a). vowel(e). vowel(i). vowel(o). vowel(u).
consonant(C) :- maplist(dif(C), [a,e,i,o,u]).
For example:
?- consonant(C).
dif(C, u),
dif(C, o),
dif(C, i),
dif(C, e),
dif(C, a).
whereas the version you posted incorrectly says that there is no consonant:
?- consonant(C).
false.
The rules you outline are readily described in Prolog:
% rule 1: vowel-consonant-vowel (break after second vowel)
rule([V1,C,V2|Rest], Bs0, Bs, Rest) :-
vowel(V1), consonant(C), vowel(V2),
reverse([V2,C,V1|Bs0], Bs).
% rule 2: vowel-consonant-consonant-vowel (break between the consonants)
rule([V1,C1,C2,V2|Rest], Bs0, Bs, [C2,V2|Rest]) :-
vowel(V1), consonant(C1), consonant(C2), vowel(V2),
reverse([C1,V1|Bs0], Bs).
% alternative: no break at this position
rule([L|Ls], Bs0, Bs, Rest) :-
rule(Ls, [L|Bs0], Bs, Rest).
Exercise: Why am I writing [V2,C,V1|_] instead of [V1,C,V2|...] in the call of reverse/2?
Now, it only remains to describe the list of resulting syllables. This is easy with dcg notation:
word_breaks([]) --> [].
word_breaks([L|Ls]) --> [Bs],
{ rule([L|Ls], [], Bs, Rest) },
word_breaks(Rest).
word_breaks([L|Ls]) --> [[L|Ls]].
Now the point: Since this program is completely pure and does not incorrectly commit prematurely, we can use it to show that there are also other admissible hyphenations:
?- phrase(word_breaks("calculator"), Hs).
Hs = [[c, a, l], [c, u, l, a], [t, o, r]] ;
Hs = [[c, a, l], [c, u, l, a, t, o], [r]] ;
Hs = [[c, a, l], [c, u, l, a, t, o, r]] ;
Hs = [[c, a, l, c, u, l, a], [t, o, r]] ;
Hs = [[c, a, l, c, u, l, a, t, o], [r]] ;
Hs = [[c, a, l, c, u, l, a, t, o, r]].
In Prolog, it is good practice to retain the generality of your code so that you can readily observe alternative solutions. See logical-purity.
I guess its time for a DCG push back solution. The push back is used in the second rule of break//1. It is to reflect that we look at four characters but only consume two characters:
vowel(a). vowel(e). vowel(i). vowel(o). vowel(u).
consonant(C) :- \+ vowel(C).
break([V1,C,V2]) -->
[V1,C,V2],
{vowel(V1), consonant(C), vowel(V2)}.
break([V1,C1]), [C2,V2] -->
[V1,C1,C2,V2],
{vowel(V1), consonant(C1), consonant(C2), vowel(V2)}.
syllables([L|R]) --> break(L), !, syllables(R).
syllables([[C|L]|R]) --> [C], syllables([L|R]).
syllables([[]]) --> [].
So the overall solution doesn't need some extra predicates such as append/3 or reverse/2. We have also placed a cut to prune the search, which can be done because of the character catchall in the second rule of syllables//1.
Here are some example runs:
Jekejeke Prolog 2, Laufzeitbibliothek 1.1.6
(c) 1985-2016, XLOG Technologies GmbH, Schweiz
?- set_prolog_flag(double_quotes, chars).
Ja
?- phrase(syllables(R), "calculator").
R = [[c,a,l],[c,u,l,a],[t,o,r]] ;
Nein
?- phrase(syllables(R), "kitchensink").
R = [[k,i,t,c,h,e,n],[s,i,n,k]] ;
Nein
P.S.: In some older draft standards this DCG technique was
called "right-hand-context", and instead of the verb "push
back", the verb "prefixing" was used. In a newer draft standard
this is called "semicontext", and instead of the verb "push back",
the verb "restoring" is used.
https://www.complang.tuwien.ac.at/ulrich/iso-prolog/dcgs/dcgsdraft-2015-11-10.pdf
I think you could write it more simply.Here is my implementation:
syllable( Input, Final_Word):-
atom_chars( Input, Char_list),
(split(Char_list, Word)-> atom_chars( Final_Word, Word);
Final_Word=Input).
split([],[]).
split([X,Y,Z|T],[X,Y,Z,'-'|T1]):-
vowel(X),vowel(Z),
atom_chars( Input, T),
syllable(Input,T2),
atom_chars( T2, T1).
split([X,Y,Z,W|T],[X,Y,'-',Z|T1]):-
vowel(X),\+vowel(Y),\+vowel(Z),vowel(W),
atom_chars( Input, [W|T]),
syllable(Input,T2),
atom_chars( T2, T1).
split([X|T],[X|T1]):- \+vowel(X),split(T,T1).
split/2 splits the word adding '-' where it could be added following the above rules you stated and returns a list to syllable. atom_chars/2 transforms the list to a word. If the word couldn't be split then the output is the input.
Example:
?- syllable(calculator,L).
L = 'calcu-lato-r'.
I'm don't understand why you wrote 'calculator = cal-cula-tor ' since it doesn't follows the rules stated, since "cal" is not vowel-constant-vowel but constant-vowel-constant and same for the rest of thr word...
I have to define some more constraints for my list.
I want to split my list is separate lists.
Example:
List=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]]
I need three Lists which i get from the main list:
[[_,0],[_,0],[_,0]] and [[_,0]] and [[2,0],[4,0]]
SO I always need a group of lists between a term with [X,1].
It would be great if u could give me a tip. Don’t want the solution, only a tip how to solve this.
Jörg
This implementation tries to preserve logical-purity without restricting the list items to be [_,_], like
#false's answer does.
I can see that imposing above restriction does make a lot of sense... still I would like to lift it---and attack the more general problem.
The following is based on if_/3, splitlistIf/3 and reified predicate, marker_truth/2.
marker_truth(M,T) reifies the "marker"-ness of M into the truth value T (true or false).
is_marker([_,1]). % non-reified
marker_truth([_,1],true). % reified: variant #1
marker_truth(Xs,false) :-
dif(Xs,[_,1]).
Easy enough! Let's try splitlistIf/3 and marker_truth/2 together in a query:
?- Ls=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]],
splitlistIf(marker_truth,Ls,Pss).
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [ [[_A,0],[_B,0],[_C,0]], [[_D,0]], [[2,0],[4,0]]] ? ; % OK
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [ [[_A,0],[_B,0],[_C,0]], [[_D,0],[9,1],[2,0],[4,0]]],
prolog:dif([9,1],[_E,1]) ? ; % BAD
%% query aborted (6 other BAD answers omitted)
D'oh!
The second answer shown above is certainly not what we wanted.
Clearly, splitlistIf/3 should have split Ls at that point,
as the goal is_marker([9,1]) succeeds. It didn't. Instead, we got an answer with a frozen dif/2 goal that will never be woken up, because it is waiting for the instantiation of the anonymous variable _E.
Guess who's to blame! The second clause of marker_truth/2:
marker_truth(Xs,false) :- dif(Xs,[_,1]). % BAD
What can we do about it? Use our own inequality predicate that doesn't freeze on a variable which will never be instantiated:
marker_truth(Xs,Truth) :- % variant #2
freeze(Xs, marker_truth__1(Xs,Truth)).
marker_truth__1(Xs,Truth) :-
( Xs = [_|Xs0]
-> freeze(Xs0, marker_truth__2(Xs0,Truth))
; Truth = false
).
marker_truth__2(Xs,Truth) :-
( Xs = [X|Xs0]
-> when((nonvar(X);nonvar(Xs0)), marker_truth__3(X,Xs0,Truth))
; Truth = false
).
marker_truth__3(X,Xs0,Truth) :- % X or Xs0 have become nonvar
( nonvar(X)
-> ( X == 1
-> freeze(Xs0,(Xs0 == [] -> Truth = true ; Truth = false))
; Truth = false
)
; Xs0 == []
-> freeze(X,(X == 1 -> Truth = true ; Truth = false))
; Truth = false
).
All this code, for expressing the safe logical negation of is_marker([_,1])? UGLY!
Let's see if it (at least) helped above query (the one which gave so many useless answers)!
?- Ls=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]],
splitlistIf(marker_truth,Ls,Pss).
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [[ [_A,0],[_B,0],[_C,0]], [[_D,0]], [[2,0],[4,0]]] ? ;
no
It works! When considering the coding effort required, however, it is clear that either a code generation scheme or a
variant of dif/2 (which shows above behaviour) will have to be devised.
Edit 2015-05-25
Above implementation marker_truth/2 somewhat works, but leaves a lot to be desired. Consider:
?- marker_truth(M,Truth). % most general use
freeze(M, marker_truth__1(M, Truth)).
This answer is not what we would like to get. To see why not, let's look at the answers of a comparable use of integer_truth/2:
?- integer_truth(I,Truth). % most general use
Truth = true, freeze(I, integer(I)) ;
Truth = false, freeze(I, \+integer(I)).
Two answers in the most general case---that's how a reified predicate should behave like!
Let's recode marker_truth/2 accordingly:
marker_truth(Xs,Truth) :- subsumes_term([_,1],Xs), !, Truth = true.
marker_truth(Xs,Truth) :- Xs \= [_,1], !, Truth = false.
marker_truth([_,1],true).
marker_truth(Xs ,false) :- nonMarker__1(Xs).
nonMarker__1(T) :- var(T), !, freeze(T,nonMarker__1(T)).
nonMarker__1(T) :- T = [_|Arg], !, nonMarker__2(Arg).
nonMarker__1(_).
nonMarker__2(T) :- var(T), !, freeze(T,nonMarker__2(T)).
nonMarker__2(T) :- T = [_|_], !, dif(T,[1]).
nonMarker__2(_).
Let's re-run above query with the new implementation of marker_truth/2:
?- marker_truth(M,Truth). % most general use
Truth = true, M = [_A,1] ;
Truth = false, freeze(M, nonMarker__1(M)).
It is not clear what you mean by a "group of lists". In your example you start with [1,1] which fits your criterion of [_,1]. So shouldn't there be an empty list in the beginning? Or maybe you meant that it all starts with such a marker?
And what if there are further markers around?
First you need to define the criterion for a marker element. This for both cases: When it applies and when it does not apply and thus this is an element in between.
marker([_,1]).
nonmarker([_,C]) :-
dif(1, C).
Note that with these predicates we imply that every element has to be [_,_]. You did not state it, but it does make sense.
split(Xs, As, Bs, Cs) :-
phrase(three_seqs(As, Bs, Cs), Xs).
marker -->
[E],
{marker(E)}.
three_seqs(As, Bs, Cs) -->
marker,
all_seq(nonmarker, As),
marker,
all_seq(nonmarker, Bs),
marker,
all_seq(nonmarker, Cs).
For a definition of all_seq//2 see this
In place of marker, one could write all_seq(marker,[_])
You can use a predicate like append/3. For example, to split a list on the first occurence of the atom x in it, you would say:
?- L = [a,b,c,d,x,e,f,g,x,h,i,j], once(append(Before, [x|After], L)).
L = [a, b, c, d, x, e, f, g, x|...],
Before = [a, b, c, d],
After = [e, f, g, x, h, i, j].
As #false has pointed out, putting an extra requirement might change your result, but this is what is nice about using append/3:
"Split the list on x so that the second part starts with h:
?- L = [a,b,c,d,x,e,f,g,x,h,i,j], After = [h|_], append(Before, [x|After], L).
L = [a, b, c, d, x, e, f, g, x|...],
After = [h, i, j],
Before = [a, b, c, d, x, e, f, g].
This is just the tip.
I've a problem.
I have 5 constants.
C(1).
C(2).
C(3).
C(4).
C(5).
And I've a predicate named "check" that receives two arguments.
Example:
check( [C(1), C(3), C(4), _, C(5)], ListFinal).
And now it should give me
ListFinal = [C(1), C(3), C(4), C(2), C(5)].
How do I do this? How to check for that black space to put there, the constant I haven't used? It is possible to change the implementation of the constants.
You could try
check( [] , [] ) .
check( [c(X)|Xs] , [c(X)|Rs] ) :- c(X) , check(Xs,Rs) .
You might also look at findall/3.
You should note however, that your 'constants' aren't constants in prolog. The way you've written them they are are facts. And the ones you've listed aren't syntactically valid Prolog: The functor of a term must be either a bareword atom like c(3). or an atom enclosed in single quotes like 'C'(3). (though why anybody would voluntarily choose to do something like that is beyond me.)
check(L, C) :-
check(L, [], C).
check([], _, []).
check([c(X)|T], A, [c(X)|C]) :-
c(X),
\+ memberchk(c(X), A),
check(T, [c(X)|A], C).
Some tests:
| ?- check([_, c(3), c(4), _, c(5)], ListFinal).
ListFinal = [c(1),c(3),c(4),c(2),c(5)] ? a
ListFinal = [c(2),c(3),c(4),c(1),c(5)]
no
| ?- check([c(1), c(3), c(4), _, c(5)], ListFinal).
ListFinal = [c(1),c(3),c(4),c(2),c(5)] ? a
no
| ?-
Here's a DCG approach:
remap([c(X)|T], A) --> {c(X), \+ memberchk(c(X), A)}, [c(X)], remap(T, [c(X)|A]).
remap([], _) --> [].
check(L, C) :- phrase(remap(L, []), C).
once corrected the syntax, check each argument (easy to do with maplist/3)
check(In, Out) :-
exclude(var, In, NoVars),
maplist(check_var(NoVars), In, Out).
check_var(In, X, Y) :-
var(X) -> c(Z), \+ memberchk(c(Z), In), Y = c(Z) ; Y = X.
usage example
1 ?- check([c(1),X,c(3),c(5)],L).
L = [c(1), c(2), c(3), c(5)] ;
L = [c(1), c(4), c(3), c(5)] ;
false.
Hey I'm trying to append two list with no "double" members
for example
A = [a, b, c]
B = [x, c, q]
then ->
append2(A,B,P)
P= [a,b,c,x,q]
I write this code, but it doesn't work...
not_member(_, []).
not_member(X, [Y|Ys]) :- X \= Y, not_member(X, Ys).
append2(A, [], A).
append2([], A, A).
append2([h1|ls], B, [h1|P]) :- not_member(h1, B), !, append2(ls, B, P).
append2([h1|ls], B, P) :- member(h1, P), append2(ls, B, P).
Thanks for helping :)
Assuming there are no variables in your input lists, but allowing duplicates in each list you may write:
append2(A,B,C):-
findall(Item, append2_item(A,B,Item), C).
append2_item(A,_,ItemA):-
append(HeadA, [ItemA|_], A),
\+ member(ItemA, HeadA).
append2_item(A,B,ItemB):-
append(HeadB, [ItemB|_], B),
\+ member(ItemB, HeadB),
\+ member(ItemB, A).
First clause of append2_item/3 selects (ordered) distinct items from the first list. Second clause of append2_item/3 selects (ordered) distinct items from the second list which are not present in the first list.
append2/3 just collects those elements.
Test case:
?- append2([a,b,c,a],[x,c,q,x],C).
C = [a, b, c, x, q].
Check out the pure code in my answer
to the related question "intersection and union of 2 lists"!
Telling from your requirements, predicate list_list_union/3 is just what you are looking for:
?- list_list_union([a,b,c],[x,c,q],Ls).
Ls = [a,b,c,x,q]. % succeeds deterministically
list_list_union/3 is monotone, so we get sound answers
even when using non-ground terms:
?- As = [_,_,_], Bs = [_,_,_], list_list_union(As,Bs,Ls), As = [a,b,c], Bs = [x,c,q].
As = [a,b,c], Bs = [x,c,q], Ls = [a,b,c,x,q] ; % logically sound result
false.