【问题标题】:Implement databases in prolog在 prolog 中实现数据库
【发布时间】:2017-02-27 17:05:25
【问题描述】:

我想在 Prolog 中实现某种“数据库”。

我对表格和行建模有两个想法:

% First one
client('B069','Laurent','769, rue de la LALALA','LLN','A1',10000).

% Second one
data(client,'B069',name,'Laurent').
data(client,'B069',adress,'69, rue de la LALALA').
data(client,'B069',town,'LLN').
data(client,'B069',cat,'A1').
data(client,'B069',amount,10000).

例如,对于这两个模型,我可以为具有正数的客户分别制作一个“SELECT ID FROM client WHERE amount > 0”:

% First one
client1_positive(Client) :- findall(ID,(data(client,ID,compte,Amount),Amount>0),Client).

% Second one
client2_positive(Client) :- findall(ID,(client(ID,_,_,_,_,Amount),Amount>0),Client).

它们都有相同的输出;

?- client1_positive(Clients).
Client = ['B069'].

?- client2_positive(Clients).
Client = ['B069'].

但这是我的问题,因为我对 Prolog 很陌生,所以我完全不知道如何使这种动态化,例如“SELECT name FROM client WHERE ID = 'B069'”。我可以为这个特定的 SQL 查询实现一个规则,但我找不到一种方法来实现一个更抽象的规则,以便可以解释每个查询。

对于如何在 Prolog 中对此类数据进行建模,是否有最佳实践?还有一些关于如何在 Prolog 中使请求更抽象的想法(不是对我问题的详细回答)?

非常感谢

【问题讨论】:

  • 没有必要过早使用findall。只依赖非确定性/回溯并尽可能晚地执行findall(或bagofsetof)。这样您的谓词/规则将自动组合。 findall 有点像对通常延迟回溯的计算的早期强制评估。

标签: database prolog


【解决方案1】:

想想你将如何使用关系数据库来做到这一点。您可能会有一个 Client 表,其中包含由客户 ID(密钥)、客户名称、地址、电话和其他联系信息组成的记录。您不会想要单独记录姓名、地址、电话等。那太麻烦了。

对于与客户端有某种关系(一对一、多对一、多对多……)的客户端数据,您将拥有单独的表。如果客户可能拥有多组联系信息,那么这就是联系信息和客户之间的多对一关系,因此您需要设置一个单独的 ContactInfo 表,其中“contact_info_id”作为主键,它将包含内容contact_info_id、客户ID、联系信息的记录。对于示例中的金额,您将有一个金额表,其中包含由金额 ID(键)、客户 ID、金额组成的记录。

要在 Prolog 中执行此操作,您需要以基本相同的方式构建它。设置client 数据和amount 数据:

% clients
client('B069', 'John Doe', '123 Main St', 123-456-1234).
client('B070', 'Jane Smith', '100 West Elm', 999-999-8888).
...

% amounts
amount('A010', 'B069', 10000).
amount('A010', 'B070', 10100).
...

以上可以是一对一或多对一的。

查询的等价物:SELECT name FROM client WHERE ID = 'B069' 将是:

?- client('B069', Name, Address, Phone).

您选择的正数是:

client_positive(Clients) :-
    findall(ClientId, (amount(_, ClientId, Amount), Amount > 0), Clients).

【讨论】:

  • 感谢帮助我。您是否知道使用该模型我如何获得例如客户端中的第二个参数,例如nth_arg(+Predicate,+Nth,-Argument) 之类的规则。这种规则存在吗?
  • @tomatediabolik 在这种情况下,您知道每个参数位置的含义。按索引挑选参数的用例是什么?通常,您可能有类似client_phone(ClientId, Phone) :- client(CllientId, _, _, Phone). 或类似的东西。如果你确实需要通过索引来挑选它,你可以使用arg/3 (arg(+Nth, +Term, -Argument)) 这将获得一个术语的第 n 个参数。如果没有关于您的用例的更多信息,我不知道该说些什么。
【解决方案2】:

您的第一种方法很好。如果,例如,您可能需要第二个 一个人可以有多个地址。

查询只是一个带有变量的术语:

| ?- client('B069',Name,Adress,Town,Cat,Amount).
Cat = 'A1',
Name = 'Laurent',
Town = 'LLN',
Adress = '769, rue de la LALALA',
Amount = 10000 ?

您可以使用任何参数作为查询中的键。您的 Prolog 可能不会对所有这些进行索引,这可能是也可能不是问题。

| ?- client(Key,'Laurent',_,_,_,_).
Key = 'B069' ? 

如果有多个答案,则通过回溯返回。 Findall 将它们收集在一个列表中,这可能是也可能不是您想要的。

如果您所说的“动态”是指在数据库中添加和删除内容,那么您可以assert/1retract/1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多