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