【发布时间】:2014-08-03 21:47:04
【问题描述】:
在 Prolog 中编程时,我经常编写谓词,当调用时所有参数都实例化时,其行为应该是半确定性的(否则其行为应该是非确定性的)。
一个具体的用例是我的谓词walk/3,它实现了图形遍历。由于两个顶点之间可以存在多个路径,因此实例化(+,+) 在true 之后给出了多个选择点。然而,这些都是毫无用处的。出于性能原因,调用代码必须显式使用once/1。
%! walk(+Graph:ugraph, +StartVertex, +EndVertex) is semidet.
%! walk(+Graph:ugraph, -StartVertex, +EndVertex) is nondet.
%! walk(+Graph:ugraph, +StartVertex, -EndVertex) is nondet.
%! walk(+Graph:ugraph, -StartVertex, -EndVertex) is nondet.
可以通过在调用上下文中使用 once/1 来强制执行半确定性,但我想将半确定性实现为谓词 walk/3 的属性,而不是作为必须特别对待每个调用它的时间。
除了对代码美学的关注之外,调用上下文不需要总是知道它对walk/3 的调用是否是半确定性的。例如:
%! cycle(+Graph:ugraph, +Vertex) is semidet.
%! cycle(+Graph:ugraph, -Vertex) is nondet.
cycle(Graph, Vertex):-
walk(Graph, Vertex, Vertex).
我想出了以下解决方案,它确实产生了正确的行为。
walk_wrapper(Graph, Start, End):-
call_ground_as_semidet(walk(Graph, Start, End)).
:- meta_predicate(call_ground_as_semidet(0)).
call_ground_as_semidet(Goal):-
ground(Goal), !,
Goal, !.
call_ground_as_semidet(Goal):-
Goal.
但是,这种解决方案存在不足:
- 这还不够通用,例如有时
ground应该是nonvar。 - 它不是风格,每次使用时都需要一个额外的谓词包装器。
- 也可能有点效率低下。
我的问题是:是否还有其他方法可以在 Prolog 中对经常出现的(非)确定性模式(如此处描述的模式)进行通用/高效/风格化编程?
【问题讨论】:
-
只是为了确保我理解你的问题,举一个更简单的例子:你想要一个谓词,当第一个参数为地面时,行为为
memberchk/2,当第一个参数不是时,行为为member/2地面? -
你检查过mavis pack 吗?
-
@Boris: library(xpath) 对于效率和控制产生影响的应用环境来说,它是一个很好的候选者
-
memberchk/2和member/2都不是 ISO。但至少,member/2是 Prolog 序言的一部分。 -
@CapelliC: memberchk/2 没有声明性意义:
memberchk(a,Xs),Xs=[b,a].失败但memberchk(a,Xs),Xs=[b,a].成功。
标签: coding-style prolog deterministic