3
votes

i have this fact and rules in prolog->

amino(a,ala,alanine,[gca,gcc,gcg,gct]).
amino(b,asx,asparagine,[aac,aat]).
amino(c,cys,cysteine,[tgc,tgt]).

amino(A,B,C,[H|T]):-
    amino(A,B,C,[H|T]),
    amino(A,B,C,T).

what im trying to do is to search for the name, single letter code and 3 letter code of the amino acid im trying to find from a given codon (the list).

when i query

?-amino(A,B,C,[tgc|_]).

it gives

A = c
B = cys
C = cysteine

so thats fine because tgc is the head of the list. but when i query

?-amino(A,B,C,[gct|_]).

it doesnt give anything. What im trying to do is to make prolog search for the codon in the list in the facts and print out everything in the fact (except the other codons) so im trying to make a recursion rule that would retrieve the whole fact from the query that provides an element in the tail of the list

2
try ?-amino(A,B,C,D),memberchk(gct,D).CapelliC
ah, thank you, that works. can you explain what memberchk() is for?Dowakaday
memberchk(E,L) is like once(member(E,L)), i.e. checks if E is member of L, but doesn't 'return' multiple solutions. It's implemented at lower level, to get max efficiencyCapelliC
[tgc|_] only matches a list whose first element is tgc, which you happen to have and succeeds. [gct|_], a list with gct 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
i thought that 'amino(A,B,C,[H|T]) :- amino(A,B,C,[H|T])' is not a good code but i just cant figure out what rule to keep out singleton errors. anyway, thanks.Dowakaday

2 Answers

2
votes

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):

  1. The first 3 clauses fail.
  2. 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.
  3. The first clause matches, with L being [gca|T] and T being [gcc|_].
  4. 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.

0
votes

The first thing that comes to mind when looking into this problem is: why a list representation? Maybe you can represent each possible codon element using a bit position and the Prolog 0b number notation? Then, instead of doing a O(n) search on a list, you can simply use the standard bitwise operators to find if a given element is present in a codon, which will give you O(1) search independent on the size of the codon. In a Prolog system implementing first-argument indexing (i.e. most of them), you would use an auxiliary table to translate between codon elements and the corresponding number. You can also have a reverse table if necessary.

P.S. I'm assuming here that the order of the codon elements doesn't matter...