在阅读SICP时,我遇到了逻辑编程第4.4章.然后我开始研究Prolog编程语言并尝试理解Prolog中的一些简单的任务.我发现Prolog似乎在数值计算方面遇到麻烦.
这是标准Prolog中的阶乘计算:
f(0, 1).
f(A, B) :- A > 0, C is A-1, f(C, D), B is A*D.
Run Code Online (Sandbox Code Playgroud)
我发现的问题是我需要引入两个辅助变量(C
和D
),一个新的语法(is
),并且问题是不可逆的(即,f(5,X)
按预期工作,但f(X,120)
不能).
天真的,我希望至少C is A-1, f(C, D)
可以用上面的东西代替f(A-1,D)
,但即使这样也行不通.
我的问题是:为什么我需要在数值计算中做这些额外的"东西",而不是在其他查询中呢?
我明白(并且SICP非常清楚),一般来说,"做什么"的信息不足以回答"如何做"的问题.因此,(至少一些)数学问题的陈述性知识不足以真正解决这些问题.但这引出了下一个问题:Prolog中这些额外的"东西"如何帮助我将制定局限于那些"做什么"足以回答"如何做"的问题?
所以univ运营商.我并不完全理解.
例如:
foo(PredList,[H|_]) :- bar(PredList,H).
foo(PredList,[_|T]) :- foo(PredList,T),!.
bar([H|_],Item) :- G =.. [H,Item],G.
bar([_|T],Item) :- bar(T,Item).
Run Code Online (Sandbox Code Playgroud)
这是做什么的?这样可以查看另一个谓词是否为真.我不明白".."的作用.
如果没有univ运算符,你会如何重写它?
有人可以帮助在此规则中找到错误吗?
concat([], List, List).
concat([Head|[]], List, [Head|List]).
concat([Head|Tail], List, Concat) :- concat(Tail, List, C), concat(Head, C, Concat).
Run Code Online (Sandbox Code Playgroud)
尝试连接2个列表失败:
| ?- concat([1,2], [4,7,0], What).
no
Run Code Online (Sandbox Code Playgroud) 以下是我对Prolog变量的理解.
单个下划线代表匿名变量,每次发生时都像一个新变量.
以_W这样的下划线开头的变量名不是匿名变量.或者,Prolog内部生成的变量名称(如_G189)不被视为匿名:
?- append([1,2],X,Y).
X = _G189
Y = [1, 2|_G189]
Run Code Online (Sandbox Code Playgroud)
你能帮我理解一下吗?
顺便说一下,我从一些教程中得到了上面的例子,但是当我在SWI-Prolog版本6中运行它时,我得到以下内容:
?- append([1,2],X,Y).
Y = [1, 2|X].
Run Code Online (Sandbox Code Playgroud)
感谢您.
好的,我知道这是一个非常普遍的问题,并且已经写了一些关于这个主题的论文,但我觉得这些出版物涵盖了非常基本的材料,我正在寻找更先进的东西来改善风格和效率.这就是我的论文:
这些主题涵盖的示例主题包括:尾递归和差异列表,正确使用索引,正确使用剪切,避免断言和缩回,避免CONSing,代码格式化指南(缩进,if-then-elses等),命名约定,代码记录,参数顺序,测试.
您将从Prolog的个人经历中添加什么?是否有适用于CLP编程的特殊风格指南?你知道一些常见的效率问题,知道如何处理它们吗?
更新:
这里有一些有趣的(但仍然太基础和太笼统)点:Lifeware团队的Prolog编程指南
为了突出整个问题,我想问一下"Prolog的编码指南"(Covington等人):
据我们所知,Prolog的一套连贯且相当完整的编码指南从未发布过.此外,当我们查看已发布的Prolog程序的语料库时,我们看不到事实上的标准出现.这一明显遗漏背后的最重要原因是,由于缺乏全面的语言标准,小型Prolog社区进一步分散为以个体Prolog系统为中心的子社区,其中没有一个具有支配地位.
我试图找出一种方法来检查两个列表是否相等,无论它们的元素顺序如何.
我的第一次尝试是:
areq([],[]).
areq([],[_|_]).
areq([H1|T1], L):- member(H1, L), areq(T1, L).
Run Code Online (Sandbox Code Playgroud)
但是,这只检查左侧列表中的所有元素是否都存在于右侧列表中; 意思areq([1,2,3],[1,2,3,4]) => true
.在这一点上,我需要找到一种能够以双向意义测试事物的方法.我的第二次尝试如下:
areq([],[]).
areq([],[_|_]).
areq([H1|T1], L):- member(H1, L), areq(T1, L), append([H1], T1, U), areq(U, L).
Run Code Online (Sandbox Code Playgroud)
在哪里我会尝试重建左边的那个以及最后的交换列表; 但这次失败了.
我对递归的感觉非常差,根本不知道如何改进它,尤其是Prolog.任何提示或建议都将在此时受到赞赏.
我有一个列表,在它的开头有一个未知数量的零,例如[0,0,0,1,2,0,3].我需要将这个列表去掉前导零,以便它看起来像[1,2,0,3].
这就是我所拥有的:
lead([Head | _], _) :- Head =\= 0.
lead([0 | Tail], _) :-
lead(Tail, Tail).
Run Code Online (Sandbox Code Playgroud)
其输出只是True.读取跟踪显示它正在运行,直到它有一个没有前导零的列表,但随后答案不会传播回堆栈.我对Prolog很新,所以我无法弄清楚如何做到这一点.
我试图在列表中计算反转的数量.谓词inversion(+L,-N)
统一N
了该列表中的反转次数.甲反转被定义为X > Y
与X
之前出现Y
在列表中(除非X
或Y
是0
).例如:
?- inversions([1,2,3,4,0,5,6,7,8],N).
N = 0.
?- inversions([1,2,3,0,4,6,8,5,7],N).
N = 3.
Run Code Online (Sandbox Code Playgroud)
对于我正在使用的内容,列表将始终包含9个元素,并且始终包含0-8
唯一的数字.
我对Prolog很新,我试图尽可能简洁,优雅; 似乎DCG可能会有很大帮助.我读了官方定义和一些教程网站,但仍然没有放弃了解它是什么.任何帮助将不胜感激.
我已经阅读了很多关于Prolog的失败否定的内容,其中Prolog是为了证明\+Goal
持有试图证明Goal
失败.
这与CWA(近距离世界假设)高度相关,例如,如果我们查询\+P(a)
(在哪里P
是arity 1的谓词),并且我们没有线索导致证明P(a)
Prolog假定(由于CWA)not P(a)
如此\+P(a)
成功.
从我所搜索的内容来看,这是一种解决经典逻辑弱点的方法,如果我们对此毫无头绪,P(a)
那么我们无法回答是否\+P(a)
持有.
上面描述的是在Prolog中引入非单调推理的方法.此外,有趣的部分是Clark证明Negation by Failure与经典否定相容/类似仅适用于地面条款.我明白这个例子:
X=1, \+X==1.
:应该在Prolog中返回false(在经典逻辑中).
\+X==1, X=1.
:应该在经典逻辑中返回false,但是在检查NF的时候它在Prolog中成功,X不受约束,这与classic-Pure Logic不同.
\+X==1.
:在X绑定之前,不应该给经典逻辑中的任何答案,但在Prolog中它返回false(可能打破经典逻辑的弱点),这与纯逻辑不相同/兼容.
我的尝试是模拟经典否定,感谢评论中的@false的建议,目前的实施是:
\\+(Goal) :- when(ground(Goal), \+Goal).
Run Code Online (Sandbox Code Playgroud)
一些测试:
?- \\+(X==1).
when(ground(X), \+X==1).
?- X=1, \\+(X==1).
false.
?- \\+(X==1), X=1.
false.
Run Code Online (Sandbox Code Playgroud)
我的问题:
以上是对经典否定的正确解释吗?(是否有任何明显的极端情况,它错过了?当使用/ 2时我也关注逻辑纯度,可以安全地假设上面是纯粹的吗??).
prolog ×10
list ×3
clpfd ×2
backtracking ×1
factorial ×1
iso-prolog ×1
negation ×1
prolog-dif ×1
types ×1