Prolog: "chili"表示调用堆栈和选择点的解释器

标签 prolog depth-first-search

通常的普通解释器使用 Prolog 回溯 本身进行归档倒缝。我想这就是原因 为什么它被称为“ Vanilla ”:

solve(true).
solve((A,B)) :- solve(A), solve(B).
solve(H) :- clause(H, B), solve(B).

一个不使用任何内容的“chili”解释器怎么样? Prolog 回溯。基本上是一个谓词 first/? 来获取 第一个解决方案和谓词 next/? 以获得进一步的解决方案。

如何在 Prolog 中实现这样一个解释器。解决方案不需要是纯粹的,也可以使用 findall 和 cut。尽管更纯粹的解决方案也可以说明问题。

最佳答案

这个解决方案是 Markus Triska 的 A Couple of Meta-interpreters in Prolog 中给出的解释器的一个稍微简化的版本。 (Prolog 的力量的一部分)具体化回溯。它有点冗长且效率较低,但可能比该代码更容易理解。

first(Goal, Answer, Choices) :-
    body_append(Goal, [], Goals),
    next([Goals-Goal], Answer, Choices).

next([Goals-Query|Choices0], Answer, Choices) :-
    next(Goals, Query, Answer, Choices0, Choices).

next([], Answer, Answer, Choices, Choices).
next([Goal|Goals0], Query, Answer, Choices0, Choices) :-
    findall(Goals-Query, clause_append(Goal, Goals0, Goals), Choices1),
    append(Choices1, Choices0, Choices2),
    next(Choices2, Answer, Choices).

clause_append(Goal, Goals0, Goals) :-
    clause(Goal, Body),
    body_append(Body, Goals0, Goals).

body_append((A, B), List0, List) :-
    !,
    body_append(B, List0, List1),
    body_append(A, List1, List).
body_append(true, List, List) :-
    !.
body_append(A, As, [A|As]).

这个想法是,Prolog 引擎状态被表示为一个析取的Choices列表,扮演着选择点堆栈的角色。每个选择的形式都是Goals-Query,其中Goals是仍待满足的目标的联合列表,即SLD树的该节点处的解决方案,并且Query 是原始查询项的一个实例,其变量已根据通向该节点的路径中进行的统一进行实例化。

如果选项的解析变为空,则其 Query 实例化将作为 Answer 返回,然后我们继续其他选择。请注意,当没有找到目标子句时,即“失败”,Choices1[] 统一,我们通过继续执行 中的剩余选择来“回溯” >选择0。另请注意,当列表中没有选择时,next/3 会失败。

示例 session :

?- assertz(mem(X, [X|_])), assertz(mem(X, [_|Xs]) :- mem(X, Xs)).
true.

?- first(mem(X, [1, 2, 3]), A0, S0), next(S0, A1, S1), next(S1, A2, S2).
A0 = mem(1, [1, 2, 3]),
S0 = [[mem(_G507, [2, 3])]-mem(_G507, [1, 2, 3])],
A1 = mem(2, [1, 2, 3]),
S1 = [[mem(_G579, [3])]-mem(_G579, [1, 2, 3])],
A2 = mem(3, [1, 2, 3]),
S2 = [[mem(_G651, [])]-mem(_G651, [1, 2, 3])].

这种方法的问题在于,findall/3 会大量复制解析结果,即要在析取分支中证明的目标的剩余合取。我希望看到一种更有效的解决方案,可以更巧妙地复制术语和共享变量。

关于Prolog: "chili"表示调用堆栈和选择点的解释器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55670411/

相关文章:

序言 : Enumerate All Elements of Countably Infinite Results

list - Prolog:如何删除列表的第二个元素

Prolog动态算术表达式

c++ - Palindrome Partitioning(如何弄清楚如何使用DFS)

algorithm - 访问状态机的伪代码

prolog - Prolog 的 DCG 问题

list - Prolog 谓词将检查列表 A 是否是列表 D 的前缀和的列表

algorithm - 如何在线性时间内找到从 DAG 中的节点可到达的最小值?

c - 迭代DFS算法与递归不匹配

C#图遍历——任意两个节点之间的跟踪路径