我有这个事实和规则在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).
我想做的是搜索我试图从给定密码子(列表)中找到的氨基酸的名称,单字母代码和3字母代码。
当我查询 时?-amino(A,B,C,[tgc|_]).
它给
A = c
B = cys
C = cysteine
所以这很好,因为TGC是列表的头。但是当我查询
?-amino(A,B,C,[gct|_]).
它没有给出任何东西。我想做的是对事实列表中的密码子进行序序搜索并打印出事实中的所有内容(除了其他密码子)所以我想创建一个递归规则从提供列表尾部元素的查询中检索整个事实
正如评论中所说,您在amino
中遇到了左递归的情况。正如建议的那样,您应该使用memberchk
和不同的谓词:
amino_codon([A,B,C],Codon) :-
amino(A,B,C,L),
memberchk(Codon,L).
(可选将结果包装在列表中)。
然而,你的方法的正确版本应该是:amino_codon(A,B,C,L):- amino(A,B,C,L),!.
amino_codon(A,B,C,L):- amino_codon(A,B,C,[_|L]).
这样,要么你的查询匹配一个事实,要么你尝试找到一个匹配子列表t
如果你真的想只有一个谓词,你可以这样做:
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]).
切割被添加,因为你只对找到一个匹配感兴趣。
编辑:对不起,在上面的从句中有一个错误,这是现在更正。关于削减:如果我们不增加削减,那么会发生以下情况。想象一下,在用上面的4个子句定义了amino
之后,您正在尝试匹配amino(A,B,C,[gcc|_])
(除非没有切割):
- 前三个子句失败
- 第4条说:为了匹配
amino(A,B,C,[gcg|_])
,让我们试着找到一个amino(A,B,C,L)
匹配的子句,这样L
的尾部就是T
。 - 第一个子句匹配,
L
为[gca|T]
,T
为[gcc|_]
。 - 但是,你还有3个其他条款可以尝试!您将回溯并尝试将
L
和T
与其他子句匹配,这些子句将递归地调用第4子句,直到用尽所有可能的选择。你在这里没有多个解决方案,即使你有,你也只对返回一个感兴趣。
如果谓词没有切割,则调用谓词必须调用once(amino(...))
,或者自己使用切割。请注意,最好让调用者来做这种决定,而不要显式地添加无用的剪切。
在研究这个问题时,首先想到的是:为什么要使用列表表示?也许您可以使用位位置和Prolog 0b
数字表示法表示每个可能的密码子元素?然后,您可以简单地使用标准的按位运算符来查找给定元素是否存在于密码子中,而不是在列表上进行O(n)搜索,这将为您提供与密码子大小无关的O(1)搜索。在实现首参数索引(即大多数)的Prolog系统中,您将使用辅助表在密码子元素和相应的数字之间进行转换。如有必要,您也可以有一个反向表。
注:我假设密码子元素的顺序不重要。