Prolog 基于在事实内部的列表中提供元素的查询检索整个事实

Prolog 基于在事实内部的列表中提供元素的查询检索整个事实,prolog,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). 我要做的是从给定的密码子(列表)中搜索氨基酸的名称、单字母代码和三字母代码 当我询问 ?-amino(A,B,C,[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,[H|T]):-
    amino(A,B,C,[H|T]),
    amino(A,B,C,T).
我要做的是从给定的密码子(列表)中搜索氨基酸的名称、单字母代码和三字母代码

当我询问

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

A = c
B = cys
C = cysteine
这很好,因为tgc是榜首。但当我询问

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

它什么也不给。我试图做的是让prolog搜索事实列表中的密码子,并打印出事实中的所有内容(除了其他密码子),因此我试图创建一个递归规则,从查询中检索整个事实,该查询提供了列表尾部的一个元素,如注释中所述,在
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]).
添加剪切是因为您只对查找一个匹配项感兴趣


编辑:对不起,上面的条款有错误,现在更正。 关于切割:如果我们不添加切割,则会发生以下情况。 假设您在定义了
amino
后,试图将
amino(A,B,C,[gcc| |)]
与上述4个子句进行匹配(不带切割的除外):

  • 前3项条款失败
  • 第四条说:为了匹配
    氨基(A,B,C,[gcg| |)]
    ,让我们试着找到
    氨基(A,B,C,L)
    匹配的子句,这样
    L
    的尾部就是
    T
  • 第一个子句匹配,
    L
    [gca | T]
    T
    [gcc | |]
  • 但是,您还有3个其他条款要尝试!您将回溯并尝试将
    L
    T
    与其他子句匹配,这些子句将递归调用第4子句,直到用尽所有可能的选择。 这里没有多个解决方案,即使有,也只对返回一个感兴趣

  • 如果谓词没有切割,则调用谓词必须调用
    一次(氨基(…)
    ,或者使用切割本身。请注意,最好将此类决定留给调用方,而不要明确地添加无用的剪切。

    在研究此问题时,首先想到的是:为什么要使用列表表示?也许您可以使用位位置和Prolog
    0b
    数字符号来表示每个可能的密码子元素?然后,不用对列表进行O(n)搜索,只需使用标准的位运算符来查找给定元素是否存在于密码子中,这将提供独立于密码子大小的O(1)搜索。在实现第一个参数索引(即大多数参数)的Prolog系统中,您将使用一个辅助表在密码子元素和相应的数字之间进行转换。如有必要,您还可以使用反向表格


    另外,我在这里假设密码子元素的顺序并不重要…

    试试
    ?-氨基(A,B,C,D),memberchk(gct,D)。
    啊,谢谢,这很有效。你能解释一下memberchk()的作用吗?memberchk(E,L)类似于once(member(E,L)),即检查E是否是L的成员,但不“返回”多个解决方案。它是在较低的级别上实现的,以获得最大的效率
    [tgc|!]
    只匹配第一个元素为
    tgc
    的列表,而您恰好拥有并成功了该列表
    [gct| |]
    ,一个以
    gct
    作为其第一个元素的列表,与您的事实或规则中的任何列表都不匹配
    memberchk
    允许您确定元素是否在列表中的任何位置。我建议你用不同于规则的方式来命名你的事实。目前,你有一个循环引用:
    amino(a,B,C,[H | T]):-amino(a,B,C,[H | T]),…
    我认为‘amino(a,B,C,[H | T]):-amino(a,B,C,[H | T])不是一个好的代码,但我只是想不出什么规则来避免单态错误。不管怎样,谢谢。哇,谢谢!但是你能解释一下这里的切割的用法吗?我还在学习,所以我对剪切有点问题。哦,通过添加剪切,你只需节省时间,而不是在你已经得到goali used列表“分组”密码子时,用prolog在整个数据库中搜索更多答案。另外,prolog对我来说是非常新的,所以我真的不知道它有很多可用的东西。不过,你的建议听起来很有用,我会研究一下的,谢谢!