如何将属性附加到术语?

时间:2017-05-19 10:22:38

标签: 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具有可在其他地方设置的属性,或者可以保留未设置。

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

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

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

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

4 个答案:

答案 0 :(得分:6)

使用“非常长的列表”,您确实找到了一个可能的表示形式,可让您直接使用Prolog的内置统一来为您执行任务。< / p>

正如您所说,这需要付出代价:它不可读,容易出错,浪费等等。

有很多可能的方法可以解决这个问题,我想给你两个指示,希望你发现它与你的任务有关。

选项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),然后,只有在必要时,才采用更容易出错且更不通用的低级方法。

答案 1 :(得分:1)

你可能会说“统一”,但你的意思是与统一在Prolog中通常意味着什么不同,这就是为什么你的问题可能会被误认为是另一个问题。你可以用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,你添加或替换这不是你想要的。

?- R =_{eyes:blue}.put(_{hair:blonde}).
R = _7436{eyes:blue, hair:blonde}.

(这个没关系)

?- R =_{eyes:blue}.put(_{eyes:brown}).
R = _7436{eyes:brown}.

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

你想要什么我不知道用文字调用什么,但它是在键值对中的键上找到联合的某种形式。但你可以用dicts来做,我想如果你先做P1 >:< P2然后put_dict(P1, P2, Result)

?- P1 = _{eyes:blue},
   P2 = _{hair:blonde,eyes:brown},
   P1 >:< P2, put_dict(P1, P2, Result). 
false.

?- P1 = _{eyes:blue},
   P2 = _{hair:blonde},
   P1 >:< P2, put_dict(P1, P2, Result).
Result = _10044{eyes:blue, hair:blonde}.

?- P1 = _{eyes:blue},
   P2 = _{hair:blonde,eyes:blue},
   P1 >:< P2, put_dict(P1, P2, Result).
Result = _10046{eyes:blue, hair:blonde}.

如果这是你要求的,请回答,因为我真的不确定?但实际上更重要的是,你想要更仔细地考虑一下你试图建模的真正的问题,因为可能吗? (只是可能吗?)你在解决方案方面的想法不如另一个解决方案那么好,这个解决方案会使问题成为一个较小的问题或者已经存在的更好的解决方案的问题。如果您在问题中提供更多关于问题的背景信息,也许会有所帮助,因为现在有足够的关于您如何解决问题的背景,但我不知道您在解决的问题。

答案 2 :(得分:1)

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

hair(bald)
hair(blonde)
eyes(blue)
eyes(green)
...

这将排除像

这样的统一
hair(blonde) = hair(red)

你可以很容易地编写自己的谓词来组合两个列表,这也可以阻止/过滤掉同一属性的多个实例。

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

答案 3 :(得分:1)

认为我理解你的问题,但我不认为我理解你的困难。您可以使用dicts,使用assoc,以及成对列表来实现您想要的效果....您说:

  

条款T1和T2具有相同的属性X值

这里有dicts,比如answer by @User9213

?- _{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.

换句话说,比较一个&#34;属性&#34;在两个词组中,你只需说Dict1.X = Dict2.X。请注意,这也适用于X变量:

?- X = a, _{a:1, b:2}.X = _{a:1, b:432432}.X.
X = a.

同样适用于已经提到的任何其他选项:使用library(assoc)(只获取该键的值并进行比较),甚至是对的列表(只需执行member(Key-Value, List)并比较值)

然后,你也说,

  

条款T1和T2相同

现在你真的可以比较一下。对于assocs,我不确定如果它们具有相同的内容,两个assoc是否总是相同,但是你可以制作列表并比较它们。如果你把你的对列表按键分类,你可以比较,就像dicts一样。

最后,你说:

  

其中T1和T2具有可在其他地方设置的属性,或者可以保留未设置。

这是含糊不清的。如果未设置属性,只需将其保留在dict / assoc / list之外。 &#34;设置在别处&#34;我真的没有。

您需要编写一些代码并了解如何完成任务。通过代码示例显示您的困难将帮助您获得具体且有用的答案。