如何修剪错误的答案?我的代码错了吗?

How to prune wrong answers? Is my code wrong?

所以我试图使我的 item_list_itemCount 关系尽可能通用并且它确实有效,至少在某个时间点之前是这样。这是代码:

% associates an item, a list and the number of times the item appears in that list.
item_list_count(_ , [], 0).
item_list_count(Item, [Item|T], Count) :-
    TCount #>= 0, 
    Count #= TCount + 1, 
    item_list_count(Item, T, TCount).
item_list_count(Item, [_|T], Count) :- 
    Count #>= 0,
    item_list_count(Item, T, Count).

例如,查询 item_list_count(1, [1,1,1,2,2,3], Count). 给出了一个正确的第一个解决方案和其他错误的回溯解决方案。

?- item_list_count(1, [1,1,1,2,2,3], Count).
Count = 3 ;
Count = 2 ;
Count = 2 ;
Count = 1 ;
Count = 2 ;
Count = 1 ;
Count = 1 ;
Count = 0 ;
false.

关于为什么会这样,我有一些假设。 Prolog 事先并不知道 1 可能恰好出现 N 次,因此它尝试将自身递归地应用于每个子列表。但是,解决方案的数量与子列表的数量不同(总共有7个),我得到了8个答案。

我还想扩展这个问题,询问有关 prolog 的优秀、强大和完整的教科书。我最近一直在问很多问题,我意识到我的知识缺乏在序言编程时会迷失方向,所以我不想在我的知识上有任何漏洞。有没有什么可靠的书籍可以让第六学期的 CS 本科生使用?

提前致谢!

你的第三个子句触发回溯。这样的事情可以防止:

item_list_count(Item, [NotItem|T], Count) :- 
    Item \= NotItem,
    item_list_count(Item, T, Count).

对于每个副本,您有 2 个选择点。因此对于三个 1s 你有 2^3 = 8 个解决方案。它与列表本身的大小无关。

您也可以承诺第二个条款本身。

item_list_count(Item, [Item|T], Count) :-
    !,                                  % prune the choice points 
    ...