如何使Prolog能够为查询生成所有可能的解决方案

时间:2014-12-06 16:25:21

标签: prolog

我希望能够生成所有可能的元素列表,在最后两个元素之间加上“和”(如在普通语言中)。任何列表中都不应有重复的元素。所以'三,二,四'是一个正确的列表,就像'二和一',或'五,三,四,一,二'。我不是在寻找单元素列表。

我写了以下程序。当我查询Prolog有关特定列表时,它会正确告诉我它是否是有效列表。但是,当我查询列表(X)时,它只生成包含两个元素的列表。

有人可以建议一种方法,使用给定的元素生成所有可能的列表吗?谢谢!

我有

之类的事实
element([one]).
element([two]).
element([three]).
element([four]), etc. etc.

我生成列表L的谓词是:

list(L):-
     element(E1),
     element(E2),
     E1 \= E2,
     append(E1, [and], X),
     append(X, E2, L).

%recursive case
list(L):-
     element(E),
     append(E, [','], X),
     append(X, Y, L),
     list(Y),
     not_in(E, Y).

not_in([X], [Y]):- X \= Y.
not_in([X], [H|T]):-
     [X] \= [H],
     not_in([X], T).

1 个答案:

答案 0 :(得分:1)

循环错误

您的代码循环是因为list(L)是根据list(Y)(递归定义)定义的。 element(E)选择第一个匹配项,即[one],然后将其预先添加到新列表Y,无限制。您正在检查最后一行EY是否再次出现,但之前的循环显示为

list(L):-
  element(E),
  append(E, [','], X),
  append(X, Y, L),
  list(Y),
  not_in(E, Y).

正确实施

由于多次使用append/3会变得混乱,我在这里使用DCGs。诀窍是保留已经使用的元素的列表,以便我们可以检查重复出现预先。这样可以避免在尝试检查此之后发生的循环行为

list -->
  list([]).

list(T) -->
  element(T, H),
  [and],
  element([H|T], _).
list(T) -->
  element(T, H),
  [','],
  list([H|T]).

element(L, X) -->
  cardinal(X),
  {\+ memberchk(X, L)}.

cardinal(1) --> [one].
cardinal(2) --> [two].
cardinal(3) --> [three].
cardinal(4) --> [four].

使用示例:

?- phrase(list, List).
List = [one, and, two] ;
...
List = [one, ',', two, ',', three, and, four] ;
...
List = [four, ',', three, ',', two, and, one] ;
false