在Prolog DCG中,如何删除过于通用的解决方案



我有一个包含序列的文本文件。例如:

GGGGGGGGAACCCCCCCCCCTTGGGGGGGGGGGGGGGGAACCCCCCCCCCTTGGGGGGGG

我写了下面的DCG来查找AA和TT之间的序列。

:- use_module(library(pio)).
:- use_module(library(dcg/basics)).
:- portray_text(true).
process(Xs) :- phrase_from_file(find(Xs), 'string.txt').
anyseq([]) -->[].
anyseq([E|Es]) --> [E], anyseq(Es).
begin --> "AA".
end -->"TT".
find(Seq) -->
     anyseq(_),begin,anyseq(Seq),end, anyseq(_).

我查询得到:

?- process(Xs).
 Xs = "CCCCCCCCCC" ;
 Xs = "CCCCCCCCCCTTGGGGGGGGGGGGG...CCCCC" ;
 Xs = "CCCCCCCCCC" ;
false.

但我不希望它找到第二个或类似的解决方案。只有一对AA和TT之间的解决方案,而不是所有的组合。我有一种感觉,我可以在dcg-basiscs库中使用string_withoutstring,但我不知道如何使用它们。

anyseq//1与库(dcg/basics(中的string//1相同,并且共享相同的"问题"。

为了保持控制,我将引入一种"分离器之间"的状态:

elem(E) --> begin, string(E), end, !.
begin --> "AA".
end -->"TT".
find(Seq) -->
     anyseq(_),elem(Seq).
anyseq([]) -->[].
anyseq([E|Es]) --> [E], anyseq(Es).
process(Xs) :-
   phrase(find(Xs), `GGGGGGGGAACCCCCCCCCCTTGGGGGGGGGGGGGGGGAACCCCC+++CCCCCTTGGGGGGGG`,_).

现在我得到

?- process(X).
X = "CCCCCCCCCC" ;
X = "CCCCC+++CCCCC" ;
false.

请注意,匿名var是短语/3的最后一个参数:它需要适应由所使用的更严格的模式引起的"控制流"的变化:elem//1是而不是后面跟着anyseq//1,因为任何两个序列"共享"anyseq//1都会有问题。

最后,你应该改变你的语法,用正确的递归语法收集elem//1。。。。

首先,让我建议您很可能歪曲了这个问题,至少如果这是关于信使核糖核酸序列的。在那里,碱基以三重态或密码子的形式出现,起点是甲硫氨酸或甲酰甲硫氨酸,但终点是三个不同的三重态。所以你很可能想要使用这样的表示。

中间的序列可以使用all_seq//2if_/3(=)/3:来定义

mRNAseq(Cs) -->
   [methionine],
   all_seq(C^maplist(dif(C),[amber,ochre,opal]), Cs),
   ( [amber] | [ochre] | [opal]).

或:

mRNAseq(Cs) -->
   [methionine],
   all_seq(list_without([amber,ochre,opal]), Cs),
   ( [amber] | [ochre] | [opal]).
list_without(Xs, E) :-
   maplist(dif(E), Xs).

但回到你的字面陈述,以及你关于声明性名称的问题。CCD_ 6和CCD_。

% :- set_prolog_flag(double_quotes, codes).   % pick this
:- set_prolog_flag(double_quotes, chars).     % or pick that
... --> [] | [_], ... .
seq([]) -->
   [].
seq([E|Es]) -->
   [E],
   seq(Es).
mRNAcontent(Cs) -->
   ...,
   "AA",
   seq(Cs),
   "TT",
   {no_TT(Cs)},  % restriction
   ... .
no_TT([]).
no_TT([E|Es0]) :-
   if([E] = "T",
      ( Es0 = [F|Es], dif([F],"T") ),
      Es0 = Es),
   no_TT(Es).

no_TT/1的含义是:列表中没有序列"TT",末尾也没有"T"。所以no_TT("T")也会失败,因为它可能会与后续的"TT"发生冲突!

那么,为什么使用纯粹的、单调的定义是个好主意呢?你很可能会想增加限制。在纯粹的单调形式中,限制是无害的。但在另一个答案中建议的程序版本中,你会得到完全不同的结果,没有任何限制。

最新更新