prolog - 如何将属性附加到术语上?

标签 prolog

我想将大约 50 个不同属性中的属性附加到我的条款中。通常,对于给定术语仅使用其中的一小部分。有很多方法可以表示这些属性,但我对其中任何一个都不满意。

为了便于讨论,这里有一组属性及其可能的值:

hair: bald, blonde, brune, red
eyes: blue, green, brown
first_name: John, Dick, Harry

有很多方法可以表示这些属性,例如使用成对的列表:

[eyes-blue, hair-blonde]

似乎唯一有效的表示方法是使用一个非常长的列表,其中每个索引用于特定属性:

?- T1=[blonde,_,_], T2=[_,blue,_], T1=T2.
T1 = T2, T2 = [blonde, blue, _1266]

?- T1=[X,_,_], X=blue.
T1 = [blue, _1230, _1236],
X = blue

但是它有 50 个属性,不可读,而且很容易出错(在我的例子中,一整套谓词专用于每个属性,有时专用于属性的每个值)。

我使用此类功能的方式是通过设置诸如“术语 T1 和 T2 具有相同的属性 X 值”或“术语 T1 和 T2 相同”之类的条件,其中 T1 和 T2 具有可以可以在其他地方设置,也可以不设置。

使用字典不起作用,因为未设置的键被认为不存在:

?- T1 = _{eyes:blue, hair:blonde}, T2 = _{eyes:blue}, T1 = T2.
false.

为了实现这一点,我需要使用 50 个(大部分是不相关的)属性和自由变量来初始化每个项,以防其中一些属性被使用。

我还有什么其他选择?如果有比 prolog 更接近我的需求的东西,我愿意使用不同的逻辑编程语言。

最佳答案

通过“很长的列表”,您确实找到了一种可能的表示方式,可以让您直接使用Prolog的内置统一来为您执行任务。

正如您所注意到的,这是有代价的:不可读、容易出错、浪费等。

解决该任务的可能方法有很多,我想为您提供两个建议,希望您能找到与您的任务相关的建议。

选项 1:使用对列表

这实际上已经在您的帖子中提到了。 hair-blonde 等形式的对是表示可用数据的自然方式。按照惯例,(-)/2 经常用于表示 Prolog 中的

所缺少的只是精确描述“合并”这些对的含义。您称之为“统一”,所以让我们使用这个术语,尽管它当然与 (=)/2 提供的语法统一不同。定义我们想要的关系的一种方法是:

unify_pairs([], APs, APs).
unify_pairs([A1-P1|APs1], APs2, APs) :-
        if_(selectd_t(A1-P1, APs2, APs2Rest),
            APs=[A1-P1|Rest],
            if_(attr_exists_t(A1, APs2),
                false,
                APs = [A1-P1|Rest])),
            unify_pairs(APs1, APs2Rest, Rest).

attr_exists_t(A, APs, T) :-
        pairs_keys(APs, As),
        memberd_t(A, As, T).

selectd_t(E, Xs0, Xs, T) :-
   i_selectd_t(Xs0, Xs, E, T).

i_selectd_t([], [], _, false).
i_selectd_t([X|Xs], Rest, E, T) :-
   if_(X=E, (T=true,Rest=Xs), (Rest = [X|Rs],i_selectd_t(Xs, Rs, E, T))).

这使用 library(reif)以及两个辅助谓词来区分不同的情况。

您的测试用例按要求工作。例如:

?- unify_pairs([hair-blonde], [eyes-blue], Ps).
Ps = [hair-blonde, eyes-blue].

?- unify_pairs([eyes-blue], [eyes-brown], Ps).
false.

重要的是,我们可以在各个方向使用它,因此我们还可以发布显着的更通用的查询。例如:

?- unify_pairs([T1-P1], [T2-P2], TPs).
T1 = T2,
P1 = P2,
TPs = [T2-P2] ;
TPs = [T1-P1, T2-P2],
dif(T2, T1),
dif(f(T2, P2), f(T1, P1)).

这样的答案有助于我们更好地理解这种关系,并更彻底地测试它。

选项 2:再次使用对列表

我想包含的第二个指针位于 library(ordsets) 中。以及多个 Prolog 系统附带的类似库。

再次允许您使用列表,甚至列表。重要的是,列表在所有 Prolog 系统中都可用。由于这些库将集合表示为有序列表,因此各种操作都非常高效。

但是,在这种情况下您可能付出的代价是第一种方法中解释的一般性。我建议您首先尝试更通用的方法(即选项 1),然后,仅在必要时才采用更容易出错且不太通用的较低级别方法。

关于prolog - 如何将属性附加到术语上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44067541/

相关文章:

list - 序言not_member不做工作

arrays - 序言中的快速二维数组

macos - 带有黑色突出显示的 Mac Prolog 控制台文本

prolog - Prolog 中的简单主谓词示例

prolog - 为什么我无法用 Prolog 得到 Ship Puzzle 的答案?

database - SWI Prolog 程序可以从外部数据库中获取事实吗?

Prolog - 通过演绎减少知识库

prolog - 序言: DCG Syntax Error

prolog - 只显示一些有效的表达式

prolog - Prolog中的 "false"和 "no"有什么区别