Prolog 如何将属性附加到术语?

Prolog 如何将属性附加到术语?,prolog,Prolog,我想将属性附加到我的术语中,从一组大约50个不同的属性。通常只有一小部分用于给定的术语。有很多方法可以表示这些属性,但我对其中任何一种都不满意 为了便于讨论,以下是一组属性及其可能的值: hair: bald, blonde, brune, red eyes: blue, green, brown first_name: John, Dick, Harry 有许多方法可以表示这些属性,例如使用对列表: [eyes-blue, hair-blonde] 唯一有效的表示方法是使用一个很长的列表,

我想将属性附加到我的术语中,从一组大约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具有可以在别处设置的属性,或者可以不设置属性

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

?- T1 = _{eyes:blue, hair:blonde}, T2 = _{eyes:blue}, T1 = T2.
false.
为了实现这一点,我需要用50个(大部分是不相关的)带有自由变量的属性来初始化每个术语,以防使用其中的一些属性

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

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

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

解决这项任务有很多可能的方法,我想给你们两点建议,希望你们能找到与任务相关的方法

选项1:使用成对列表 事实上,你的帖子中已经提到了这一点。成对的表格<代码>金发碧眼等是表示可用数据的自然方式。按照惯例,
(-)/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))). 重要的是,我们可以在各个方向上使用它,因此我们也可以发布更一般的查询。例如:

?- 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)). ?统一_对([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:再次使用配对列表 我想包括的第二个指针可以在和一些PrologSystem附带的类似库中找到

这同样允许您使用列表,甚至是成对的列表。重要的是,列表在所有PrologSystem中都可用。由于这些库将集合表示为OrderedList的方式,各种操作都非常有效

然而,在这种情况下,您可能支付的价格是第一种方法中解释的一般性。我建议您首先尝试更通用的方法(即选项1),然后,只有在必要时,才求助于更容易出错且不太通用的低级方法。

您可能会说“统一”但是你的意思和统一在序言中通常的意思不同,这就是为什么你的问题可能被误认为是一个不同的问题。您可以使用SWI Prolog dicts做一些事情:

?- _{hair:blonde, eyes:blue} >:< _{eyes:blue}.
true.

?- _{hair:blonde, eyes:blue} >:< _{eyes:blue, hair:Color}.
Color = blonde.

?- _{hair:blonde, eyes:blue} >:< _{eyes:blue, hair:bald}.
false.
(这个还行)

(这不是你想要的,是吗?)

你想要什么我不知道用词怎么称呼,但这是在键值对中的键上找到并集的某种形式。但是你可以用dict来做,我想如果你先做
P1>:
,然后
把dict(P1,P2,Result)

?-P1={眼睛:蓝色},
P2={头发:金发,眼睛:棕色},
P1>:

请回答,如果这是你问的,因为我真的不确定?但实际上更重要的是,你要更仔细地思考你试图建模的真正问题,因为也许?(只是可能?)你是从一个解决方案的角度来考虑的,这个解决方案不如另一个解决方案好,它会使问题变得更小,或者是一个已有更好解决方案的问题。如果您在问题中提供更多关于您的问题的上下文,可能会有所帮助,因为现在有足够的上下文说明您是如何试图解决问题的,但我不知道您真正在解决什么问题。

您可以将属性设为一个算术术语,如下所示:

hair(bald)
hair(blonde)
eyes(blue)
eyes(green)
...
这就排除了像这样的统一

hair(blonde) = hair(red)
您可以很容易地编写自己的谓词来组合两个列表,这也可以阻止/过滤出同一属性的多个实例

在具有强类型的语言中,这是一种很好的表示,但我不确定它在Prolog中是否有用。无论如何,这是可能的。

我想我理解你的问题,但我不理解你的困难。你可以通过dicts、assocs、成对列表来实现你想要的。。。。你说:

术语T1和T2对于属性X具有相同的值

这里是关于dicts的,比如:

换句话说,要比较两个dict的“属性”,只需说
Dict1.X=Dict2.X
。请注意,这也适用于
X
变量:

?- X = a, _{a:1, b:2}.X = _{a:1, b:432432}.X.
X = a.
这同样适用于前面提到的任何其他选项:使用
库(assoc)
(只需获取该键的值并进行比较),或者
hair(bald)
hair(blonde)
eyes(blue)
eyes(green)
...
hair(blonde) = hair(red)
?- _{a:1, foo:2, bar:3}.a = _{a:2, foo:22, baz:33}.a.
false.

?- _{a:1, foo:2, bar:3}.a = _{a:1, foo:22, baz:33}.a.
true.
?- X = a, _{a:1, b:2}.X = _{a:1, b:432432}.X.
X = a.