1

我想在 Prolog 中构建自己的协程。我想添加一些额外的功能。

4

2 回答 2

5

为协程编写一个普通的解释器应该在每门 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

于 2016-02-01T14:35:02.770 回答
3

一种可能的解决方案是使用某些 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 系统自己的术语扩展机制实现来做同样的事情。任何人?

于 2014-05-03T21:52:05.293 回答