我可以得到结果为真,但当我试图让它变为假时,我觉得它是无限循环。
repeat(L,N,Result):-
rHelp(L,N,[],Result).
rHelp(_,_,Result,Result).
rHelp([H|T],N,L1,L2):-
dupe(H,N,[],L3),
append(L1,L3,L4),
rHelp(T,N,L4,L2).
dupe(_,0,L,L).
dupe(H,N,L,Result):-
N1 is N-1,
append(L,[H],L1),
dupe(H,N1,L1,Result).
示例测试:
repeat( [a, b, c], 2, [a, a, b, b, c, c] )
repeat( [1, a, 2, b], 0, [ ] )
repeat( [1, 1, 2], 3, [1, 1, 1, 1, 1, 1, 2, 2, 2] )
都是真的。我只是试图得到一个错误的结果。
答案 0 :(得分:0)
使程序失败的一个原因是它描述了太多不正确的解决方案:
?- repeat([a, b, c], 2, Result).
Result = [] ;
Result = [a, a] ;
Result = [a, a, b, b] ;
Result = [a, a, b, b, c, c] ;
% nontermination
您接受太多解决方案的原因是rHelp/4
的第一个条款:
rHelp(_,_,Result,Result).
在这里你说任何输入列表,在你有中间结果Result
的计算中的任何一点,这是一个正确的解决方案。但这种情况并非如此。一旦用尽整个输入列表,中间结果只是一个完整的结果。该条款应为:
rHelp([], N, Result, Result).
请注意,我发现这主要是通过模式匹配。相邻的子句如
foo(_, Bar).
foo([H|T], Bar) :- ...
只是看不正确。为什么_
不是空列表?在大多数情况下,像这样的谓词在头部会有相互排斥的模式,而事实并非如此。
有了这个问题,我们可以再次尝试测试:
?- repeat([a, b, c], 2, Result).
Result = [a, a, b, b, c, c] ;
% nontermination
更好!但它仍然在寻找更多的解决方案,尽管没有。这也是条款不相互排斥的情况:
dupe(_,0,L,L).
dupe(H,N,L,Result):-
N1 is N-1,
...
如果第二个参数不是0
,则第二个条款适用。如果第二个参数是0
,则第一个子句适用......但第二个参数也适用!在使用第一个子句找到解决方案后,Prolog将使用N = 0
回溯并执行第二个子句。然后N1
将变为-1
,并且您的程序将以递归方式查找负无穷大。
修复是在第二个子句中添加一个保护N > 0
。通过这两个更改,测试可以按预期工作:
?- repeat([a, b, c], 2, Result).
Result = [a, a, b, b, c, c] ;
false.
这里要注意的一个重点是,通过使用不太具体的查询,更容易理解谓词的行为。无需为Result
参数指定固定列表:保持免费并查看Prolog为您提供的内容!