Prolog:失败的语句执行两次

Prolog: failing statement executes twice

我是 Prolog 的初学者(使用 SWI-Prolog),我遇到以下问题:

我有一个规则定义如下:

start:-
   write("Enter first list: "), read_list(List1), 
   write("Enter second list: "), read_list(List2), 
   equal_length(List1, List2), 
   compare(List1, List2, Alike),
   write(" The lists are "), write(Alike).

start:- write("The lists should have the same length!!").

这是我阅读列表的方式:

read_list([H|T]):- read(H), H\=[], read_list(T).
read_list([]).

Compare 是一组将比较列表的规则,但它永远不会执行,我什至为此替换了它:

compare(_, _, "the same").

这是 equal_length 的样子:

equal_length([_|T1], [_|T2]):- equal_length(T1, T2).
equal_length([], []).

因此当列表的长度不同时它会失败。 问题是,当启动失败时,它再次执行第一次出现(List1 和 List2 已经绑定)!

我试过像这样更简单的东西:

hi:- 1>2, write("Nonsense").
hi:- write("Of course it doesn't work").

并且输出的是第二个字符串。 为什么第一个不那样做?

编辑:

经过进一步测试,我发现这种奇怪的行为只会在从该自定义方法读取列表时发生,并且只会在读取多个列表时发生。

你的代码的问题是缺乏对回溯的管理。当您的语句失败时,Prolog 将尝试为满足 equal_length 的列表获取新值。 这是一个使用 ! 运算符处理回溯的示例:

start:-
      read_list_data( List1, List2 ),
      equal_length(List1, List2),
      compare2(List1, List2, Alike),
      write( List1 ), nl,
      write(" The lists are "),
      write(Alike).

start:- write("The lists should have the same length!!").

read_list([H|T]):- read(H),
      H\=[],
      read_list(T).
read_list([]).

compare2(_, _, 'the same').

equal_length([_|T1], [_|T2]):- equal_length(T1, T2).
equal_length([], []).

read_list_data( List1, List2 ) :-
      write("Enter first list: "),
      read_list(List1),
      write("Enter second list: "),
      read_list(List2),
      !.

解释:

! 标记通过让 Prolog 知道它必须提交到目前为止所做的选择(即保留列表的值)来避免回溯不良行为。 我在这个 here 上找到了一个很好的信息来源,其中用树图解释了回溯。