2

我正在尝试编写一个谓词is_multi(M),定义为:

  • 的每个元素都M具有 的形式X / N,其中X是一个原子,并且N是一个大于 0 的整数;
  • M不包含具有相同原子的两个元素,为什么

    is_multi([]).
    is_multi([a / 2, b / 2]).
    

    很满意,但是

    is_multi([a, b/2]).
    is_multi([a/0, b/2]).
    is_multi([a/2, 2/4])
    is_multi([a/2, b/3, a/2])
    is_multi([a/3, b/-4, c/1])
    

    不是。

这是我到目前为止所写的:

is_multi(M) :- M = [].
is_multi(M) :-
    M = [Head|Tail],
    Head = X/N,
    integer(N),
    N > 0,
    is_multi(Tail).

但是如果具有相同的原子,它不会比较两个元素。例如,is_multi([a/2, a/3])不满意。我被困了一天;有人可以给我一些提示吗?

4

2 回答 2

4

首先,您可以通过将一些统一从主体移到头部来大大简化您的代码。

is_multi([]).
is_multi([X/N|Tail]) :-
  integer(N), N > 0,
  is_multi(Tail).

清理它揭示了你在这里没有做的一件事,这在你的规范中是检查它X是一个原子。atom(X)通过添加到主体来修复。

好的,所以这处理了基本形式,但不能确保原子不重复。最简单的做法是将其拆分为两项检查,一项检查每个项目的格式是否正确,另一项检查列表是否格式正确。事实上,我倾向于使用maplist/2检查单个元素的谓词。但你真正需要做的就是这样的事情:

is_valid([]).
is_valid([X/_|T]) :- is_valid(T), \+ memberchk(X/_, T).

这只是说空列表是有效的,如果尾部是有效的,如果 X 在尾部没有出现,则列表是有效的。

如果这就是你想要的,请停止阅读。如果你想重构,我会这样做:

well_formed(X/N) :- atom(X), integer(N), N > 0.

no_repeating_numerators([]).
no_repeating_numerators([X/_|T]) :- no_repeating_numerators(T), \+ memberchk(X/_, T).

is_multi(L) :- maplist(well_formed, L), no_repeating_numerators(L).
于 2013-07-16T04:30:56.740 回答
3

只是为了完成丹尼尔的指导性答案(我 +1),我想展示如何通过一些库谓词来解决您的任务:

is_multi(L) :-
    forall(select(E, L, R),
           (E = A/N, atom(A), integer(N), N > 0, \+memberchk(A/_, R))).
于 2013-07-16T07:18:12.793 回答