属性变量:库接口/实现/可移植性

Attributed variables: library interfaces / implementations / portability

当我浏览一些 related questions recently, I stumbled upon this answer by @mat to question How to represent directed cyclic graph in Prolog with direct access to neighbour verticies .

到目前为止,我个人在 Prolog 中使用属性变量的经验非常有限。但是@mat 给出的用例引起了我的兴趣。所以我试着用它来回答另一个问题,ordering lists with constraint logic programming

首先,好消息:我第一次使用属性变量的结果和我想要的一样。

然后,不太好的消息: 当我通过回答发布时,我意识到 Prolog 中有几个 API 和属性变量的实现。

我觉得我在这里不知所措...我特别想知道以下内容:

这里有很多问号...请分享您的经验/立场? 提前致谢!


编辑 2015-04-22

这是上面提到的 answer 的代码片段:

init_att_var(X,Z) :-
    put_attr(Z,value,X).

get_att_value(Var,Value) :-
    get_attr(Var,value,Value).

到目前为止我"only"使用put_attr/3 and get_attr/3, but---according to the SICStus Prolog documentation on attributed variables---SICStus offers put_attr/2 and get_attr/2

所以即使这个非常浅的用例需要一些仿真层(一种方式或另一个)。

我想重点谈谈我在为属性变量使用不同接口时注意到的一个重要的一般点:在为属性变量设计接口时,实现者还应记住以下几点:

  • 在推理同时统一时是否可以考虑属性,如[X,Y] = [0,1]

这在 SICStus Prolog 中是可能的,因为在调用 verify_attributes/3 之前,此类绑定是 未完成的。在 hProlog 提供的接口中(attr_unify_hook/2,在 统一后调用 并且所有绑定都已经到位)很难考虑 [= 的(以前的)属性13=]在推理X统一到attr_unify_hook/2时,因为此时Y已经不是变量了!这对于可以仅根据基础值做出决策的求解器来说可能就足够了,但对于需要额外数据(通常存储在属性中)以查看统一是否应该成功的求解器来说,这是一个严重的限制,然后不再容易获得这些数据.一个明显的例子:布尔统一与决策图。

截至 2016 年,verify-attributes branch of SWI-Prolog also supports verify_attributes/3, thanks to great implementation work by Douglas Miles。该分支已准备好进行测试,并打算在其正常有效地工作后立即合并到 master 中。为了与 hProlog 兼容,该分支还支持 attr_unify_hook/2:它通过在编译时将此类定义重写为更通用的 verify_attributes/3 来做到这一点。

在性能方面,很明显 verify_attributes/3 可能有一个缺点,因为同时让多个变量接地可能会让您更快地看到(在 attr_unify_hook/2 中)统一不能成功。但是,我很乐意随时将这种通常可以忽略不计的优势换成更通用的界面为您提供的更高的可靠性、易用性和更多的功能,并且无论如何这已经是最上面的 SICStus Prolog 中的标准行为它的通用性也是周围更快的 Prolog 系统之一。

SICStus Prolog 还具有一个重要的谓词,称为 project_attributes/2:顶层使用它来将约束投影到查询变量。 SWI-Prolog 在最近的版本中也支持这一点。

SWI 接口还有一个巨大的优势:attribute_goals//1 和因此 copy_term/3 给你的剩余目标始终是一个 list。这有助于用户避免代码中的默认情况,并鼓励使用更具声明性的界面,因为纯约束目标列表不能包含控制结构

有趣的是,除了 句法 之外,这两个接口都不允许您解释统一。就我个人而言,我认为在某些情况下,您可能希望以不同于句法的方式来解释统一,但是,也可能有很好的反对意见。

属性变量的其他接口谓词大多很容易与不同系统的简单包装器谓词互换。

关于属性变量库的另一个观点是每个模块可以定义多少个属性。在 SWI-Prolog/YAP 并引用 SWI 文档的情况下:

Each attribute is associated to a module, and the hook (attr_unify_hook/2) is executed in this module.

这对于 CLP(FD) 等库的实现者来说是一个严重的限制,因为它强制使用额外的模块来实现具有多个属性的唯一目的,而不是能够在实现它们的模块中定义尽可能多的属性图书馆。 SICStus Prolog 接口不存在此限制,它提供了一个指令 attribute/1,允许每个模块声明任意数量的属性。

您可以在 ECLiPSe 中找到最古老、最精细的属性变量实现之一,它构成了实现约束求解器的更广泛基础结构的一部分。

本设计的主要特点是:

  • 属性必须声明,在return编译器支持高效访问
  • 属性变量的语法,以便可以读写它们
  • 一组更完整的属性操作处理程序,这样属性不仅可以用于统一,还可以用于其他通用操作,例如术语复制和包含测试
  • 明确区分可变属性和暂停目标的概念
  • 用于十几个 ECLiPSe 的库

This paper (section 4) 和 ECLiPSe 文档有更多详细信息。

Jekejeke Minlog 有 state-less 或 thin 属性变量。不完全是,一个属性变量可以有零个、一个或多个钩子,它们可以是闭包,因此可以携带一点状态。

但通常情况下,实现会管理 elsewere 的状态。为了这 目的 Jekejeke Minlog 允许从变量创建引用类型, 以便它们可以用作表的索引。

如果这与尾随 and/or 相结合,将释放全部潜力 前向链接。作为示例,我们已经实现了 CLP(FD)。还有一个小求解器教程。

在我们的例子中原始 ingredients 是:

1) State-less 属性变量
2) 尾随键和可变键
3) 继续队列

属性变量挂钩可能具有绑定效果,直到扩展继续队列,但只执行一次。后续队列中的目标可以是 non-deterministic。

在实现应用程序之前还有一些额外的层,这些层主要是原语的聚合以进行临时更改。

目前主要的应用都是开源的here and here:

a) 有限域约束求解器
b) Herbrand 约束
c) 暂停进球

再见