% remove(+Elem : Any, +List : list, -Out : list)
% 从List中去除所有元素Elem
remove(_,[],[]).
remove(Elem,[X|XS],Out) :-
Elem == X,
remove(Elem,XS,Out).
remove(Elem,[X|XS],[X|Out]) :-
% \+ Elem == X,
remove(Elem,XS,Out).
% count(+List : list, -C: int)
% 计算Elem在List中出现的个数
count(_,[],0).
count(Elem,[X|XS],C) :-
Elem == X,
count(Elem,XS,C0),
plus(1,C0,C).
count(Elem,[X|XS],C) :-
% \+ Elem == X,
count(Elem,XS,C).
看这俩个prolog谓词,有觉得哪里不对吗?富有经验的prologer应该已经有数了,但是笔者在这上面花费了一些让人哭笑不得的时间,就说出来供大家一笑吧。
数周前我尝试编写2个prolog谓词,第一个根据一些条件计算出一个分数,第二个使用第一个谓词作为评估函数求平均分最高的策略。因为长期观看haskell代码,于是我很快地写出了上面那俩个辅助谓词。
在线平台的测试未通过,它表示第一个谓词出现了多解,问题就出在之前没有加的
\+ Elem == X,
,没加这个条件上下pattern又一致,当
Elem == X
失败时会发生回溯,导致多解。
这是马后炮,当时我没想明白问题究竟在哪里,直接在第一个谓词那里使用了剪枝,通过了所有测试用例,但是第二个仍然有问题。于是我很自然地把注意力转移到第二个谓词上。
一天过去了,真悲哀,毫无进展。
笔者一直坚信的信条是”写不如抄,抄不如偷”,于是找来一个正确答案,开始一个个替换小函数并且给小函数写测试,再辅以writeln,在一天后发现了问题:
首先是好几处忘记剪枝/取反,导致多解,但是更令人哭笑不得的是,笔者对题目中的一条计分规则的理解根本就是错的!
西方俗语云garbage in, garbage out,然而这垃圾却能通过测试,原因正是错误多解的组合中可能涵盖正确解,在巧合下刚好通过了测试一的数据集,哼,哼,哼,啊啊啊啊啊啊啊啊!
重要的是明白自己在做什么,而不是瞎试试企图蒙混过关。