如何将属性附加到术语?

Jer*_*ome 2 prolog

我想从一组约50种不同的属性中将属性附加到我的术语中.通常只有一小部分用于给定的术语.有很多方法可以表示这些属性,但我对它们中的任何一个都不满意.

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

hair: bald, blonde, brune, red
eyes: blue, green, brown
first_name: John, Dick, Harry
Run Code Online (Sandbox Code Playgroud)

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

[eyes-blue, hair-blonde]
Run Code Online (Sandbox Code Playgroud)

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

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

?- T1=[X,_,_], X=blue.
T1 = [blue, _1230, _1236],
X = blue
Run Code Online (Sandbox Code Playgroud)

但它有50个属性是不可读的,并且非常错误(在我的情况下,一整套谓词专用于每个属性,有时属于属性的每个值).

我使用这种功能的方式是使条件如"条款T1和T2具有相同的属性X值",或"条款T1和T2相同",其中T1和T2具有可在其他地方设置的属性,或者可以不设置.

使用dicts不起作用,因为未设置的密钥被认为是不存在的:

?- T1 = _{eyes:blue, hair:blonde}, T2 = _{eyes:blue}, T1 = T2.
false.
Run Code Online (Sandbox Code Playgroud)

为了实现这一点,我需要使用带有自由变量的50个(大多数是不相关的)属性来初始化每个术语,并且有可能会使用其中一些.

我还有其他选择吗?如果有更接近我的需求而不是prolog,我愿意使用不同的逻辑编程语言.

mat*_*mat 6

通过"非常长的列表",您确实找到了一种可能的表示形式,可让您直接使用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),然后,只有在必要时,才采用更容易出错且更不通用的低级方法.