如何添加和比较列表中的成员

时间:2013-07-16 03:53:21

标签: list prolog

我正在尝试编写一个谓词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])不满意。我被困了一天;有人能给我一些提示吗?

2 个答案:

答案 0 :(得分: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).

答案 1 :(得分:3)

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

is_multi(L) :-
    forall(select(E, L, R),
           (E = A/N, atom(A), integer(N), N > 0, \+memberchk(A/_, R))).