Prolog,X在列表中的Y之前

时间:2015-11-10 15:46:02

标签: list prolog

我无法理解prolog,我必须找到X是否在列表中的Y之前。

所以我有一个带有空列表的基本案例

before(X, Y, [ ]).

现在我知道我想检查X的索引和List中的Y的索引,如果indexX < indexY我想要成功。

有人可以解释一个简单的方法吗?

4 个答案:

答案 0 :(得分:3)

您可以使用append/3找到X及其后的剩余列表,然后找到Y。

before(X, Y, L):-
  append(_, [X|Tail], L),
  append(_, [Y|_], Tail).

答案 1 :(得分:3)

使用DCG,它看起来像这样(使用名为...的谓词来表示符号/视觉方便性):

before(X, Y) --> ..., [X], ..., [Y], ... .
... --> [].
... --> [_], ... .

| ?- phrase(before(X, Y), [a,b,c]).

X = a
Y = b ? ;

X = a
Y = c ? ;

X = b
Y = c ? ;

(1 ms) no

如果您愿意,可以将其包装在谓词中:

before(X, Y, L) :- phrase(before(X, Y), L).

<小时/> 正如@CapelliC所指出的,如果X出现在Y之前的列表中至少有一个案例,则上述谓词会成功。但是,如果定义是 X,则会在列表Y之前看到,那么另一种DCG实现可能是:

before(X, Y) --> anything_but(Y), [X], ..., [Y], ... .

anything_but(_) --> [].
anything_but(Y) --> [X], { dif(X, Y) }, anything_but(Y).

... --> [].
... --> [_], ... .

结果是:

| ?-  phrase(before(X,Y), [b,a,b]).

X = b
Y = b ? a

X = a
Y = b

no

答案 2 :(得分:0)

在Prolog中,列表处理在大多数情况下是在不使用索引的情况下完成的:您使用递归,并尝试将其表示为逻辑表达式。如果您不想使用内置插件,可以写下:

before(X,Y,[X|T]) :-
    !,
    contains(Y,T).
before(X,Y,[_|T]) :-
    before(X,Y,T).

contains(Y,[Y|_]) :-
    !.
contains(Y,[_|T]) :-
    contains(Y,T).

代码使用定义的contains/2谓词来检查列表L是否包含Y。现在before/2谓词包含两个子句。第一个子句指定列表的第一个元素是X,在这种情况下,我们只需要检查列表的其余部分是否包含Y。如果列表的第一个元素不是X,则列表会进一步移动,并且通过使用递归,我们会尝试找到存在X的位置。

请注意,此谓词要求XY都是列表的元素。此外,可以有多个XY。因此,before(a,b,[b,a,a,b])会成功,因为有aba位于b之前。

修改

如果要以相反的方式使用谓词(查询时尚),则应省略剪切:

before(X,Y,[X|T]) :-
    contains(Y,T).
before(X,Y,[_|T]) :-
    before(X,Y,T).

contains(Y,[Y|_]).
contains(Y,[_|T]) :-
    contains(Y,T).

然后你可以查询:

?- before(X,Y,[a,b,c]).
X = a,
Y = b ;
X = a,
Y = c ;
X = b,
Y = c ;
false.

答案 3 :(得分:0)

这是一个简单的解决方案,不使用任何内置谓词。

如果您以更通用的术语重新解决问题,这会有所帮助。

常见的prolog习语是一个公共谓词,它调用一个完成所有工作的worker谓词。通常,工作者谓词将携带维持状态的附加变量。在这种情况下,我们不需要维护状态,但如果我们使实际解决方案更通用,它会简化事情:而不是根据XY来定义问题,重新定义一个任意长度的列表,定义必须在目标列表中找到事物的顺序。

然后,只需要并行递归两个列表以确定是否满足优先约束。通用解决方案(适用于包含任意数量约束的列表)有3种情况:

  
      
  • 约束列表为空:成功!
  •   
  • 约束列表的头部与列表的头部统一   测试。这表明已经满足约束。删除两个   约束和它刚匹配的项目(正在测试的列表的头部)   然后递减。
  •   
  • 最后,只需删除正在测试的列表的头部并递归。
  •   

解决方案如下所示:

x_before_y( X , Y, Zs ) :- satisfies_constraints( [X,Y] , Zs ) .

satisfies_constraints( []     , _      ) .
satisfies_constraints( [C|Cs] , [C|Xs] ) :- satisfies_constraints(Cs,Xs) .
satisfies_constraints( Cs     , [_|Xs] ) :- satisfies_constraints(Cs,Xs) .

在回溯中,这将找到所有可能的解决方案。如果这是不可取的,那么第二个条款中的一个切入将消除选择点:

satisfies_constraints( []     , _      ) .
satisfies_constraints( [C|Cs] , [C|Xs] ) :- !, satisfies_constraints(Cs,Xs) .
satisfies_constraints( Cs     , [_|Xs] ) :-    satisfies_constraints(Cs,Xs) .

在第3条款中引入不可统一性的测试:

satisfies_constraints( []     , _      ) .
satisfies_constraints( [C|Cs] , [C|Xs] ) :- satisfies_constraints(Cs,Xs) .
satisfies_constraints( [C|Cs] , [X|Xs] ) :-
  C \= X ,
  satisfies_constraints([C|Cs],Xs)
  .