12

我只是参与使用 Prolog 来处理不仅仅是最简单形式的数据(事实),并且正在寻找经验丰富的 Prologers 的一些指导......

如果我想动态管理数据或事实,我有几个主要的选择,例如:

  • 在 Prolog 中将数据作为断言进行管理,或者
  • 从 Prolog 到数据库的接口,或者
  • 可能是两者的结合

如果我在 Prolog 中将事实作为断言来管理,那么我还有一个问题是表示这些事实的最佳方式。假设我有一个person有名字、姓氏和年龄的人。我可以断言它为:

person(first_name(_), last_name(_), age(_)).

或者对 person 的属性有一个隐含的假设:

person(_, _, _).  % first name, last name, age

如果我想将一个人与其他事物联系起来,我真的需要一个人的钥匙。所以我可能倾向于断言一个人为:

person(id(_), ...).  % Maintain id as a uniq person key; or done implicitly as above

当然,现在我让我的 Prolog 断言看起来像关系数据库表条目。这让我想知道我是否采取了错误的方法并使事实的表达过于复杂。

所以真的,我的问题是:在 Prolog 中管理中到复杂数据时,是否有一些最佳实践需要考虑?命名约定是它的一小部分。我读过像 Prolog 中的断言/撤回这样的位是低效的。因此,我还想知道如何处理数据组织本身,例如何时使用外部 SQL 数据库与仅使用 Prolog 表示。

附录

我会假设由于关系数据库使用它们的原因,像在关系数据库中所做的那样,对记录使用键是可取的。这意味着必须维护密钥。对于每种情况,在 Prolog 中手动(显式)执行此操作似乎很麻烦,那么这通常是如何完成的呢?还是我的假设正确?

4

6 回答 6

12

考虑为谓词使用更具描述性的名称,例如:

id_fname_lname_age(_, _, _, _).

这明确表示参数是什么,而不需要任何额外的结构。

在我看来,命名谓词的一个好的经验法则是按照参数出现的顺序来描述参数,使用声明性名称,用下划线分隔。

编辑:至于您的其他问题:与简单地在本质上不需要对子句数据库进行任何修改的谓词之间传递参数的良好声明性编程风格相比,assertz/1速度很慢(并且有许多其他缺点)。当您因为像关系数据库系统一样使用 Prolog 而确实需要断言其他事实时,这是一种方法(此处的其他答案中提到了其他选项),并且在效率上可能与任何其他关系数据库系统相当适用于许多使用场景。如前所述,一些现代 Prolog 系统对所有参数执行即时索引,因此您无需显式声明任何“键”。assertz/1

于 2013-06-08T14:07:35.590 回答
6

在使用断言/撤回时,没有人解决您关于效率的问题。

对于 SWI-Prolog,简而言之,事实是被索引的(即时意味着当它们第一次被查询时),并且查找非常有效(基于哈希表)。默认情况下,索引仅在第一个参数上,但有内置的解决方法(我想将所有内容保持在规范化形式会很痛苦)。

经验法则似乎是,只要您的所有数据都适合内存,并且您不经常断言/撤回,它就是最佳选择。您可以使用 library(persistency) 使谓词持久化。

至于约束和触发器等东西,我想你必须编写自己的谓词,但是使用 Prolog 的语法,这不应该比在 SQL 中定义这些更冗长(尽管我在关系数据库方面的经验非常有限,所以我可能会说我的屁股)。

于 2013-06-09T17:02:54.483 回答
3

Prolog基于关系数据模型。

然后,关系数据模型 - 平庸 - 足以满足 Prolog,尽管 - 就我个人而言 - 我想念您使用 SQL DML 获得的元数据工具。文档 - 如果可用 - 很容易不同步,并且处理与许多列的关系很痛苦,部分原因是 Prolog 是无类型的,部分原因是您不能(轻松)“按名称调用”列 - Prolog 错过了“投影运算符” ' 在关系代数(当然还有 SQL)中可用。SWI-Prolog 有库(记录)来克服这个问题,但我不太喜欢它。

一般来说,当涉及到一些“现实世界”的数据建模时,比如深度嵌套(XML/HTML/SVG/其他)表示,或者维度索引实体,比如空间和地理数据库,或者大图,就像今天的本体所要求的那样,关系数据建模可能是不够的。

您必须提供缺失的细节,这在技术上可能非常复杂。如果你需要一些你的 Prolog 引擎不提供的索引,你将被埋在用低级语言(通常是 C)编写困难的接口中。那么为什么不使用一些更简单的语言,以及基于该复杂数据建模的可随时使用(和调试)的库呢?他们有很多。

因此,SWI-Prolog 的开发由实用性驱动,而不是作为 Prolog 应用程序最初关注的抽象语言(自然和合成)研究,具有专门的接口 - 例如 - 用于 Web 和本体。请参阅软件包页面,其中大多数都是精心设计的复杂数据接口。

从软件工程的角度来看,此类接口的可用性会影响语言选择。只是为了强调 SWI-Prolog 的声誉有多高,它最近被提名(如 Python)获得荷兰 ICT 创新奖

正在进行的开发——比如在基于 DCG 的 HTML 生成中嵌入 javascript 的准引用——以及来自 SWI-Prolog 邮件列表的大力支持是非常有价值的!

就个人而言,我致力于通过应用到实际任务来学习RDF建模。

于 2013-06-09T07:38:37.323 回答
2

Boris - 我最近在 swipl 列表中做出了这个断言,或者几乎是这样断言,“保存它的最佳方法是使用 qsave_program,而不仅仅是包含所有事实的文本文件。” Jan 提出了一个令人信服的论点,即使用 library(persist) 是一个更好的选择。我认为 save_state 作为持久性机制的日子已经一去不复返了。

于 2013-06-09T19:07:50.667 回答
1

如果您对使用第一种格式感兴趣,我强烈建议您在谓词中使用列表,如下所示:

person([first_name(_), last_name(_), age(_)]).

这样您就可以根据需要添加或删除内容。它还可以更轻松地从特定片段中获取信息:

?- person(P), member(first_name(Name), P).
P = [first_name(dave), last_name(hardy), middle_name(robert), age(27)],
Name = dave .

这种方法还可以容易地维护数据列表,以防您不想永久声明数据。

于 2013-06-09T02:34:53.847 回答
0

下载WordNet 的 Prolog 版本,看看里面发生了什么:

  • 什么是关系数据库表是一个单独的文件。
  • 如果必须,生成一个整数 ID 并将其放在第一个位置。WordNet 选择只为词义赋予它们自己的 ID。
  • 记录文档中每个位置的内容

这里的其他建议对我来说似乎是不必要的负担。如果您只满足于 Prolog 访问这些数据,那么以 Prolog 的格式存储它,让您在使用 Prolog 时更轻松。如果 Prolog 只是访问数据的几种语言中的一种,请将其保存在关系数据库中。从 Prolog 获得它的负担将被其他一切变得更容易所抵消。

使用 Prolog 伪造迁移并不难。利用listing/1

%   save_database(+functor, +filename)
%
% Records all the facts of Functor in Filename
save_database(Functor, Filename) :-
  telling(OldStream), tell(Filename),
  listing(Functor),
  told, tell(OldStream).

例如,save_database(foo/1, 'foo.pl').您可以在此基础上轻松编写数据迁移。我真的没有看到可以证明其他答案中建议的更大复杂性的用例。

于 2013-06-09T04:16:06.620 回答