我希望能够生成所有可能的元素列表,在最后两个元素之间加上“和”(如在普通语言中)。任何列表中都不应有重复的元素。所以'三,二,四'是一个正确的列表,就像'二和一',或'五,三,四,一,二'。我不是在寻找单元素列表。
我写了以下程序。当我查询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).
答案 0 :(得分:1)
您的代码循环是因为list(L)
是根据list(Y)
(递归定义)定义的。 element(E)
选择第一个匹配项,即[one]
,然后将其预先添加到新列表Y
,无限制。您正在检查最后一行E
中Y
是否再次出现,但之前的循环显示为。
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