如何在prolog中解析列表,直到不失败
我正在尝试解析列表,例如:如何在prolog中解析列表,直到不失败,prolog,Prolog,我正在尝试解析列表,例如: [1,3,3,2,2,7,2,9] 假设我有以下代码,其中isTwo将打印No,如果不是两个,则会失败。如果不是两个,我希望它失败。如果是2,它将打印Yes并成功 isTwo(2) :- write('Yes'), !. isTwo(_) :- write('No'), fail. 我的问题是,我已经定义了一个迭代器,我想解析一个完整的列表来找到第一个成功 iter([]). iter([Head|Tail]) :- isTwo(He
[1,3,3,2,2,7,2,9]
假设我有以下代码,其中isTwo将打印No
,如果不是两个,则会失败。如果不是两个,我希望它失败。如果是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
我这里的问题是:如何在prolog中继续解析,同时仍然确保isTwo()
(它不等于2)仍然会失败,这样在这种情况下我就可以得到nononoyesnoyesno
之类的输出。最好不使用if-then-else子句
这可能有助于:
预期输出:nononoyesnoyesno
观察到的结果:
No
一个简单的解决方案是在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).
如果您想要更简洁的解决方案,可以使用
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
静默变量),则会出现问题
为什么不这样:
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) ).
只要摆脱
失败
。你让这件事对你自己来说比你需要的更难。