纯粹的Prolog程序以清晰的方式区分术语的平等和不平等,导致执行效率低下; 即使所有相关术语都是基础的.
关于SO的最近一个例子是这个答案.在此定义中,所有答案和所有失败都是正确的.考虑:
?- Es = [E1,E2], occurrences(E, Es, Fs).
Es = Fs, Fs = [E, E],
E1 = E2, E2 = E ;
Es = [E, E2],
E1 = E,
Fs = [E],
dif(E, E2) ;
Es = [E1, E],
E2 = E,
Fs = [E],
dif(E, E1) ;
Es = [E1, E2],
Fs = [],
dif(E, E1),
dif(E, E2).
Run Code Online (Sandbox Code Playgroud)
虽然程序从声明的角度来看是完美无缺的,但它在B,SICStus,SWI,YAP等当前系统上的直接执行效率却不必要地低效.对于以下目标,为列表的每个元素保留一个选择点.
?- occurrences(a,[a,a,a,a,a],M). M = [a, a, a, a, a] ; false. …
我面临的问题有点微不足道.我想在Prolog中使用逻辑,但似乎not/1
不是我想要的东西:
course(ai).
course(pl).
course(os).
have(X,Y) :- course(X),course(Y),not(X = Y).
Run Code Online (Sandbox Code Playgroud)
我查询:
have(X,Y), write(X-Y), nl , fail.
Run Code Online (Sandbox Code Playgroud)
我没有得到我想要的结果:(
different(Xs, Ys) :-
member(X, Xs),
non_member(X, Ys).
different(Xs, Ys) :-
member(Y, Ys),
non_member(Y, Xs).
Run Code Online (Sandbox Code Playgroud)
虽然这个定义使用member/2
和non_member/2
几乎是1从声明的观点完美的,它产生于特定查询的冗余解决方案,并选择留点周围.
什么是改进的定义(以纯粹的方式可能使用if_/3
和(=)/3
),使得完全相同的解决方案集被描述different/2
但至少对于地面查询是确定的(因此不会留下任何无用的选择点)并且省略(如有可能)任何多余的答案?
1
实际上,different([a|nonlist],[]), different([],[b|nonlist])
成功了.它同样可能失败.所以两者都失败的解决方案很好(甚至可能更精细).
标准术语顺序(ISO/IEC 13211-1 7.2术语顺序)是在所有术语(包括变量)上定义的.虽然有很好的用途 - 想想实现setof/3
,但这使得许多其他清洁和逻辑用途的内置插件在8.4 Term比较中声明性的噩梦与imps(命令式构造的简短形式)四处都有.8.4术语比较功能:
8.4术语比较
8.4.1(@ = <)/ 2,(==)/ 2,(\ ==)/ 2,(@ <)/ 2,(@>)/ 2,(@> =)/ 2.
8.4.2比较/ 3.
8.4.3 sort/2.
8.4.4 keysort/2.
举个例子,考虑一下:
?- X @< a.
true.
Run Code Online (Sandbox Code Playgroud)
这成功了,因为
7.2期限订单
命令term_precedes(3.181)定义
术语X
术语是否在术语之前Y
.如果
X
且Y
是相同的术语,则X
term_precedesY
和Y
term_precedesX
都是假的.如果
X
和Y
有不同的类型:X
term_precedesY
当且仅当该
类型X
先于类型Y
按以下顺序:
variable
先floating point
先于integer
先 …
考虑一下我尝试过的:
dif_to_orto(A, B, C) :-
( dif(A, B)
; dif(A, C)
).
Run Code Online (Sandbox Code Playgroud)
虽然从声明性的角度来看,这个定义很好,但它包含许多冗余。考虑到:
?- dif_to_orto(A, B, C), A = 1, B = 2, C = 2.
A = 1, B = 2, C = 2
; A = 1, B = 2, C = 2. % unexpected redundant solution
Run Code Online (Sandbox Code Playgroud)
即使在这种情况下也不行:
?- dif_to_orto(A, B, C), A = 1, B = 2, C = 3.
A = 1, B = 2, C = 3
; A = 1, B = 2, C …
Run Code Online (Sandbox Code Playgroud) lcs([ H|L1],[ H|L2],[H|Lcs]) :-
!,
lcs(L1,L2,Lcs).
lcs([H1|L1],[H2|L2],Lcs):-
lcs( L1 ,[H2|L2],Lcs1),
lcs([H1|L1], L2 ,Lcs2),
longest(Lcs1,Lcs2,Lcs),
!.
lcs(_,_,[]).
longest(L1,L2,Longest) :-
length(L1,Length1),
length(L2,Length2),
( Length1 > Length2
-> Longest = L1
; Longest = L2
).
Run Code Online (Sandbox Code Playgroud)
到目前为止这是我的代码.我怎样才能优化它以便打印前缀,例如:
["interview", "interrupt", "integrate", "intermediate"]
Run Code Online (Sandbox Code Playgroud)
应该回来 "inte"
Prolog有点生疏,有一段时间没做过:)
如果我想确保两个变量不实例化到同一个术语,那么首选方法是什么?
假设我需要在图中找到有向边,并且节点不能有自己的边:
node(a, x, y). node(b, z, x). node(c, y, y).
Run Code Online (Sandbox Code Playgroud)
(这里的边是 - > c,b - > a,但不是 c - > c)
以下作品:
edge(A, B) :- node(A, _, X), node(B, X, _), A \== B.
Run Code Online (Sandbox Code Playgroud)
这也有效[swi-prolog]:
edge(A, B) :- dif(A, B), node(A, _, X), node(B, X, _).
Run Code Online (Sandbox Code Playgroud)
这显然不起作用(因为A和B都没有被实例化?):
edge(A, B) :- A \== B, node(A, _, X), node(B, X, _).
Run Code Online (Sandbox Code Playgroud)
我想我的第一个解决方案的问题是,使用更复杂的node
谓词,在edge
失败之前可能会发生许多不必要的统一.在dif
另一方面,是在图书馆,这表明它并不意味着在这种简单的情况下使用(虽然它,我似乎在寻找精确的功能).
我有一个列表,在它的开头有一个未知数量的零,例如[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很新,所以我无法弄清楚如何做到这一点.
它们存在吗?他们是如何实施的?
所述coroutining SWI-Prolog的(的谓词freeze
,when
,dif
等)具有的功能警卫.它们如何适合首选的Prolog编程风格?
我是很新的逻辑编程(有序言和共)和事实,即它不是纯粹的声明,并要求即使在非常简单的情况下程序上的考虑有点困惑(见本关于使用问题\==
或dif
).我错过了重要的事吗?