我想将大约 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/