我想从一组约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,我愿意使用不同的逻辑编程语言.
通过"非常长的列表",您确实找到了一种可能的表示形式,可让您直接使用Prolog的内置统一来为您执行任务.
正如你所注意到的,这是有代价的:它不可读,容易出错,浪费等.
有很多可能的方法来解决这个任务,我想给你两个指示,我希望你发现它与你的任务相关.
事实上,这已经在你的帖子中提到了.对形式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)).
这些答案有助于我们更好地理解这种关系,并对其进行更详尽的测试.
我希望包含的第二个指针位于library(ordsets)几个Prolog系统附带的类似库中.
这再次允许您使用列表,甚至是对的列表.重要的是,所有 Prolog系统都提供了列表.由于这些库将集合表示为有序列表,因此各种操作非常有效.
但是,在这种情况下您可能支付的价格是第一种方法中解释的一般性.我建议你首先尝试更通用的方法(即选项1),然后,只有在必要时,才采用更容易出错且更不通用的低级方法.