counter([],[]).
counter([H|T],[[H,C1]|R]) :- counter(T,[[H,C]|R]),!, C1 is C+1.
counter([H|T],[[H,1]|R]) :- counter(T,R).
Run Code Online (Sandbox Code Playgroud)
"!"的影响是什么?因为我在上面和下面的代码中输入相同的输出?
counter([],[]).
counter([H|T],[[H,C1]|R]) :- counter(T,[[H,C]|R]),C1 is C+1.
counter([H|T],[[H,1]|R]) :- counter(T,R).
Run Code Online (Sandbox Code Playgroud)
我是Prolog的新手.
"!"的影响是什么?
剪辑修剪了搜索空间.也就是说,在一个纯粹的单调程序中,剪切将删除一些解决方案或答案.只要那些多余就没关系.听起来很无辜和有用,不是吗?我们来看一下!
以免我忘记,[E,Nr]用来表示对是相当不寻常的,更好地使用一对E-Nr.
我们现在将比较counter_cut/2和counter_sans/2.
| ?- counter_cut([a,a],Xs).
Xs = [[a,2]].
| ?- counter_sans([a,a],Xs).
Xs = [[a, 2]]
; Xs = [[a, 1], [a, 1]]. % <<< surprise !!!
Run Code Online (Sandbox Code Playgroud)
因此,剪切版本的解决方案更少.似乎counter_cut/2保留的解决方案是正确的.在这个非常特殊的情况下.它总是会采取正确的吗?我将尝试一个最简单的更一般的查询:
| ?- counter_cut([a,B],Xs).
B = a,
Xs = [[a, 2]].
| ?- counter_sans([a,B],Xs).
B = a,
Xs = [[a, 2]]
; Xs = [[a, 1], [B, 1]].
Run Code Online (Sandbox Code Playgroud)
再一次,_sans它更加可怕,而这一次,它甚至有点正确; 最后的答案包括B = b.换一种说法,
| ?- counter_cut([a,B], Xs), B = b.
fails. % incomplete !
| ?- counter_sans([a,B], Xs), B = b.
B = b,
Xs = [[a,1],[b,1]].
Run Code Online (Sandbox Code Playgroud)
所以有时_cut版本更好,有时也更好_sans.或者更直接地说:两者都是错误的,但_sans-version至少包括所有解决方案.
这是一个"纯化"版本,它只是将最后一条规则重写为两种不同的情况:一个用于列表的末尾,另一个用于另一个不同的元素.
counter_pure([],[]).
counter_pure([H|T],[[H,C1]|R]) :- counter_pure(T,[[H,C]|R]), C1 is C+1.
counter_pure([H],[[H,1]]).
counter_pure([H,D|T],[[H,1]|R]) :- dif(H,D), counter_pure([D|T],R).
Run Code Online (Sandbox Code Playgroud)
从一个不太出名的效率观点来看.
以下是具有合理树统一的系统的效率测试用例:
?- Es = [e|Es], counter(Es, Dict).
resource_error(stack).
Run Code Online (Sandbox Code Playgroud)
相反,实现应该顺利循环,至少直到这个宇宙结束.严格地说,该查询必须产生资源错误,但只有在它计数到远大于的数字之后才会产生10^100000000.
剪切操作符!通过修剪所有选择点来提交当前的推导路径。鉴于一些事实
fact(a).\nfact(b).\nRun Code Online (Sandbox Code Playgroud)\n\n您可以比较有剪切和没有剪切的答案:
\n\n?- fact(X).\nX = a ;\nX = b.\n\n?- fact(X), !.\nX = a.\nRun Code Online (Sandbox Code Playgroud)\n\n如您所见,一般查询现在仅报告其第一次成功。尽管如此,查询
\n\n?- fact(b), !.\ntrue.\nRun Code Online (Sandbox Code Playgroud)\n\n成功了。这意味着,该削减违反了以下解释:,这意味着,该剪切违反了逻辑合取
?- X = b, fact(X), !.\nX = b.\n\n?- fact(X), !, X=b.\nfalse.\nRun Code Online (Sandbox Code Playgroud)\n\n但根据我们对合取的理解,当 B \xe2\x88\xa7 A 成立时, A \xe2\x88\xa7 B 应该准确地成立。那么为什么要这样做呢?
\n\n效率:可以使用削减,使得它们只改变执行属性,而不改变谓词的答案。例如,理查德·奥基夫 (Richard O'Keefe) 的Craft of Prolog中描述了这些所谓的绿色切割中描述了这些所谓的绿色切割。如上所述,维护带有剪切的谓词的正确性比不带有剪切的谓词要困难得多,但显然,正确性应该优先于效率。
\n\n看起来你的问题是绿色的,但我不能 100% 确定答案是否没有变化。
否定:根据封闭世界假设进行逻辑否定逻辑否定,用cut表示。您可以将 neg(X) 定义为:
\n\nneg(X) :-\n call(X),\n !,\n false.\nneg(_) :-\n true.\nRun Code Online (Sandbox Code Playgroud)\n\n因此,如果call(X)成功,我们就切掉第二条规则的选择点并得出 false。否则,什么都没有被削减,我们就会得出真理。请注意,这不是经典逻辑中的否定,并且它受到剪切的非逻辑效果的影响。假设您定义谓词land/1为其中一个大陆:
land(africa).\nland(america).\nland(antarctica).\nland(asia).\nland(australia).\nland(europe).\nRun Code Online (Sandbox Code Playgroud)\n\n然后将水定义为陆地上以外的一切:
\n\nwater(X) :-\n neg(land(X)).\nRun Code Online (Sandbox Code Playgroud)\n\n那么就可以正确得到:
\n\n?- water(pacific).\ntrue.\n\n?- water(africa).\nfalse.\nRun Code Online (Sandbox Code Playgroud)\n\n但你也可以得出:
\n\n?- water(space).\ntrue.\nRun Code Online (Sandbox Code Playgroud)\n\n这不应该成立。特别是在经典逻辑中:
\n\nland(africa) \xe2\x88\xa7\nland(america) \xe2\x88\xa7\nland(antarctica) \xe2\x88\xa7\nland(asia) \xe2\x88\xa7\nland(australia) \xe2\x88\xa7\nland(europe) \xe2\x86\x92 \xc2\xac land(space).\nRun Code Online (Sandbox Code Playgroud)\n\n无效。再次强调,如果您在 Prolog 中使用否定,您应该清楚地知道自己在做什么。