我正在尝试解析列表,例如:
[1,3,3,2,2,7,2,9]
假设我有以下代码,其中isTwo将打印No
,如果不是2则失败。如果不是两个,我希望失败。如果为2,它将打印Yes
并成功。
isTwo(2) :-
write('Yes'), !.
isTwo(_) :-
write('No'), fail.
我的问题是我在定义迭代器的过程中遇到了一些麻烦,我想解析整个列表以找到第一个成功的对象。
iter([]).
iter([Head|Tail]) :-
isTwo(Head),
iter(Tail).
这很好,但是一旦发现故障,它将停止解析列表的其余部分。如果我们返回原始列表[1,3,3,2,2,7,2,9]
,则会得到false
作为输出。
我的问题是:如何继续在序言中解析,同时仍然确保isTwo(_)
(不等于2)仍然失败,因此我可以得到类似{ {1}}在这种情况下。最好不要使用if-then-else子句。
这可能有帮助:
预期输出:NoNoNoYesYesNoYesNo
观察到的输出:NoNoNoYesYesNoYesNo
答案 0 :(得分:2)
一种简单的解决方案是在iter
中使用第二个变量,该变量将帮助您理解是否找到了不同于2的数字:
isTwo(2, X, X) :-
write('Yes').
isTwo(_, _, 0) :-
write('No').
iter([], 0):- fail,!.
iter([], 1).
iter([Head|Tail], X) :-
isTwo(Head, X, Y),
iter(Tail, Y).
iter(L) :- iter(L, 1).
答案 1 :(得分:1)
如果您想要更简洁的解决方案,可以使用maplist/2
进行以下操作:
isTwo(2) :- write('Yes'), !.
isTwo(_):- write('No').
test(L):-
maplist(isTwo,L).
?- test([1,3,3,2,2,7,2,9]).
NoNoNoYesYesNoYesNo
true
test/1
不是强制性的,我只是为了清楚起见添加了它...
答案 2 :(得分:0)
其他答案都很好,但是随意混合的副作用让我有点紧张。另外,如果您要“解析”的列表有一个自由变量(它会静默变成2
),您就会遇到问题。
为什么不这样:
is_two(X) :- X == 2, !, format("Yes").
is_two(X) :- X \== 2, !, format("No").
然后:
?- forall(member(X, [1,3,3,2,2,7,2,9]), is_two(X)).
NoNoNoYesYesNoYesNo
true.
?- forall(member(X, [Y, 2, Z]), is_two(X)).
NoYesNo
true.
使用==
和\==
进行比较而不统一。使用forall
和member
来表明您这样做是为了产生副作用。遍历列表(或使用maplist
)有点欺骗。
forall
只是使用否定(而不是削减和失败)进行失败驱动循环的一种更清晰的方法。上面的查询与:
?- \+ ( member(X, [1,3,3,2,2,7,2,9]), \+ is_two(X) ).