我想在 Prolog 中构建自己的协程。我想添加一些额外的功能。
2 回答
为协程编写一个普通的解释器应该在每门 Prolog 课程的教学清单上。这很简单,在这里你可以看到普通的普通解释器,简化:
% solve(+Term)
solve(true).
solve((A,B)) :- solve(A), solve(B).
solve(H) :- clause(H, B), solve(B).
现在对于 corouting,在通过 freeze/2 暂停目标的意义上,只需添加一个带有延迟目标的附加输入输出参数对,有关 select/3 的规范,请参见 (*):
% solve(+Term, +List, -List)
solve(G, L, R) :- select(freeze(V, F), L, H),
nonvar(V), !,
solve((F,G), H, R).
solve(freeze(V, G), L, [freeze(V,G)|L]) :- var(V), !.
solve(freeze(_, G), L, R) :- solve(G, L, R).
solve(true, L, L).
solve((A,B), L, R) :- solve(A, L, H), solve(B, H, R).
solve(H, L, R) :- clause(H, B), solve(B, L, R).
您可以使用上述香草解释器来研究不同的唤醒策略。我不确定它是否捕获了现有的 Prolog 系统。但是您可以运行以下示例:
?- freeze(X, member(X, [the(1), the(2)])), X = the(Y).
成功,通过提出以下问题:
?- solve((freeze(X, member(X, [the(1), the(2)])), X = the(Y), true), [], L).
需要 ", true" 来检查最后一次唤醒目标。如果 L 返回为空,则唤醒所有冻结的目标。否则有一些未决的冻结目标。这有时被称为挣扎。
上面的原型还通过瘦属性、undo/1 和目标注入队列对解释器的一些小支持导致了协程的自然实现。我很快就会在其他地方发布这个。
再见
(*) https://www.complang.tuwien.ac.at/ulrich/iso-prolog/prologue
一种可能的解决方案是使用某些 Prolog 系统和 Logtalk 提供的术语扩展机制来重写对freeze/2
谓词的调用,以执行您想要的额外步骤。然而,必须小心,不要将对谓词的调用扩展到另一个目标,该目标调用相同的谓词,因为递归地应用目标扩展,直到达到固定点。术语扩展机制的 Logtalk 实现通过使用编译器绕过控制结构,可以轻松避免此陷阱(具有可移植性的额外优势,因为您可以将 Logtalk 与大多数 Prolog 系统一起使用){}/1
。一个愚蠢的例子是:
:- object(my_expansions,
implements(expanding)).
goal_expansion(
freeze(Var,Goal),
( write('If you instantiate me, I will run away!\n'),
{freeze(Var,Goal)}, % goal will not be further expanded
write('Bye!\n')
)
).
:- end_object.
然后可以将此对象用作挂钩对象,用于编译包含对freeze/2
您要扩展的调用的源文件。类似的东西(假设上面的对象保存在一个名为my_expansions.lgt
的文件中,并且您要扩展的源文件名为source.lgt
):
?- logtalk_load(my_expansions), logtalk_load(source, [hook(my_expansions)]).
有关完整的详细信息,请参阅 Logtalk 文档和示例。
可能有一种干净的方式,我不知道使用 Prolog 系统自己的术语扩展机制实现来做同样的事情。任何人?