我只是参与使用Prolog来处理的不仅仅是最简单的数据形式(事实),而且正在寻找经验丰富的Prologers的一些指导......
如果我想动态管理数据或事实,我有几个主要选择,例如:I / I
如果我将事实作为Prolog中的断言来管理,我也有一个代表这些事实的最佳方式的问题。假设我有一个person
,他有一个名字,姓氏和一个年龄。我可以断言:
person(first_name(_), last_name(_), age(_)).
或隐含假设人的属性是什么:
person(_, _, _). % first name, last name, age
如果我想将一个人与其他人联系起来,我真的需要一个人的钥匙。所以我可能倾向于断言一个人:
person(id(_), ...). % Maintain id as a uniq person key; or done implicitly as above
当然,现在我正在使我的Prolog断言看起来像关系数据库表条目。这让我想知道我是否采取了错误的做法并使事实的表现过于复杂化。
所以,我的问题是:在Prolog中管理中到复杂数据时是否需要考虑一些最佳实践?命名约定是它的一小部分。我读过像Prolog中的assert / retract这样的位是低效的。所以我也想知道如何处理数据组织本身,比如什么时候采用外部SQL数据库而不是Prolog-only表示。
附录
我认为,由于关系数据库使用它们的原因,在关系数据库中使用记录密钥是可取的。这意味着必须保持密钥。对于每种情况,在Prolog中手动(显式)执行此操作似乎很麻烦,那么这通常如何完成?或者我的假设是正确的?
答案 0 :(得分:8)
考虑为谓词使用更具描述性的名称,例如:
id_fname_lname_age(_, _, _, _)
。
这明确表示参数是什么而不需要任何其他结构。
在我看来,命名谓词的一个好的经验法则是按照它们出现的顺序来描述参数,使用以下划线分隔的声明性名称。
编辑:至于你的其他问题:assertz/1
与一个很好的声明性编程风格相比,它是一个很好的声明式编程风格,而且只是在谓词之间传递参数本质上不需要对子句数据库进行任何修改。当你真的需要断言其他事实,因为你正在使用像关系数据库系统这样的Prolog,那么assertz/1
是一种方法(其他选项在这里的其他答案中提到),并且可能在效率方面具有可比性许多使用场景的任何其他关系数据库系统。如前所述,一些现代Prolog系统对所有参数执行即时索引,因此您无需显式声明任何“键”。
答案 1 :(得分:4)
使用断言/收回时,还没有人提出有关效率的问题。
对于SWI-Prolog,简而言之,事实被索引(即时查询首次查询时),查找非常有效(基于哈希表)。默认情况下,索引仅在第一个参数上,但是有内置函数可以解决这个问题(我想将所有内容保持在规范化形式中会很麻烦。)
经验法则似乎是,只要您的所有数据都适合内存,并且您不经常断言/撤回,它就是最佳选择。您可以使用库(持久性)使谓词持久化。
对于像约束和触发器等的东西,我想你必须编写自己的谓词,但是使用Prolog的语法,这不应该比在SQL中定义这些语句更冗长(我在关系数据库中的经验相当虽然有限,所以我可能会说出我的屁股。)
答案 2 :(得分:3)
在关系数据模型上,Prolog基于 。
然后关系数据模型 - 对于Prolog来说是足够的 - 虽然 - 个人 - 我错过了使用SQL DML获得的元数据工具。文档 - 如果可用 - 很容易失去同步,处理与许多列的关系很痛苦,部分原因是Prolog是无类型的,部分是因为你不能(很容易)“按名称调用”列 - Prolog错过了'投影运算符'可用于关系代数(当然还有SQL)。 SWI-Prolog有库(record)来解决这个问题,但我不太喜欢它。
通常,当涉及某些“真实世界”的数据建模时,如深度嵌套(XML / HTML / SVG /无论)表示,或维度索引的实体,如空间和地理数据库,或大型图形,如同今天的本体论,关系仅数据建模可能不充分。
您必须提供缺少的详细信息,这在技术上可能非常复杂。如果您需要一些Prolog引擎无法提供的索引,您将陷入低级语言(通常为C)编写难度接口的过程中。那么为什么不使用一些更简单的语言,随时可以使用(以及调试)这些复杂数据的库?有很多。
因此,开发受实用性驱动的SWI-Prolog,而不是作为Prolog应用程序最初焦点的抽象语言(自然和合成)研究,具有专门的接口 - 例如 - 用于Web和本体。请参阅packages页面,其中大部分都是精心设计的复杂数据接口。
从SW工程的角度来看,此类接口的可用性使在语言选择上有所不同。为了强调SWI-Prolog的声誉有多高,它最近被Dutch ICT innovation award提名(如Python)。
正在进行的开发 - 就像在基于DCG的HTML生成中嵌入javascript的准引用 - 来自SWI-Prolog邮件列表的大力支持是伟大的值加法器!
就个人而言,我正致力于学习 - 通过应用实际任务 - RDF建模。
答案 3 :(得分:2)
鲍里斯 - 我最近在swipl列表上做了这个断言,或者差不多,“保存它的最好方法是使用qsave_program而不仅仅是一个包含所有事实的文本文件。”和Jan提出了一个令人信服的论点,即使用库(persist)是一个更好的选择。我认为save_state作为持久性机制的日子已经过去了。
答案 4 :(得分: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 .
此方法还使真正易于维护数据列表,以防您不希望永久断言数据。
答案 5 :(得分:0)
下载the Prolog version of WordNet并查看其中发生的事情:
这里的其他提议对我来说似乎是不必要的负担。如果您满足于只有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').
您可以轻松地在此基础上编写数据迁移。我真的没有看到一个用例来证明其他答案中提出的更复杂的问题。