As said in the comments, you have a case of left-recursion in amino
.
As suggested, you should use memberchk
with a different predicate:
amino_codon([A,B,C],Codon) :-
amino(A,B,C,L),
memberchk(Codon,L).
(Wrapping results in a list is optional).
However, the correct version of your approach would be:
amino_codon(A,B,C,L):- amino(A,B,C,L),!.
amino_codon(A,B,C,L):- amino_codon(A,B,C,[_|L]).
That way, either your query is matched by a fact, or you try to find a match with sublist T.
If you really wanted to have only one predicate, you would do as follows:
amino(a,ala,alanine,[gca,gcc,gcg,gct]):-!.
amino(b,asx,asparagine,[aac,aat]):-!.
amino(c,cys,cysteine,[tgc,tgt]):-!.
amino(A,B,C,T) :- amino(A,B,C,[_|T]).
Cuts were added because you are only interested to find one match.
Edit: sorry, there was an error in the above clauses, this is corrected now.
About cuts: if we don't add cuts, then the following happens.
Imagine you are trying to match amino(A,B,C,[gcc|_])
after you defined amino
with the 4 clauses above (except without cuts):
- The first 3 clauses fail.
- The 4rd says: in order to match
amino(A,B,C,[gcg|_])
, let's try to find a clause where amino(A,B,C,L)
matches, such that the tail of L
is T
.
- The first clause matches, with
L
being [gca|T]
and T
being [gcc|_]
.
- But, you have still 3 other clauses to try! You will backtrack and try to match
L
and T
with other clauses, which will call recursively the 4rd clause until exhaustion of all possible choices.
You don't have multiple solutions here, and even if you had, you are only interested in returning one.
If you left your predicates without cuts, the calling predicate would have to call once(amino(...))
, or use a cut itself. Note that it might be desirable to leave this kind of decision to the caller and not explicitely add useless cuts.
?-amino(A,B,C,D),memberchk(gct,D).
– CapelliC[tgc|_]
only matches a list whose first element istgc
, which you happen to have and succeeds.[gct|_]
, a list withgct
as its first element, doesn't match any of the lists in your facts or rule.memberchk
allows you to determine if an element is anywhere within the list. And I would recommend that you name your facts differently than your rule. As it stands, you have a circular reference:amino(A,B,C,[H|T]) :- amino(A,B,C,[H|T]), ...
– lurker