为什么在Prolog中构造真值列表时会得到错误的结果?

时间:2013-01-20 03:03:19

标签: list prolog

我正在尝试创建一个谓词,如果第三个列表由TF组成,则该谓词为真,具体取决于第一个和第二个是否有两个相同索引的元素清单是平等的。像truth_list(['abc','def'],['zui','def'],L).这样的查询应该提供L=['F','T']

这是我的尝试:

truth_list([],[],_).
truth_list([H1|T1],[H2|T2],TL):-
    (H1==H2)->(H3='T');(H3='F'),
    Temp=TL,
    TL=[H3|Temp],
    truth_list(T1,T2,TL).

如果有人能解释为什么这不能按预期工作,我将不胜感激。

2 个答案:

答案 0 :(得分:2)

所以我们都在同一页面上,当我运行查询时得到了这个结果:

L = ['F'|L].

所以首先想到的是你可能正在重用变量,事实上,以下条款看起来很可疑:

Temp=TL,
TL=[H3|Temp],

Prolog中的变量并不像其他语言那样真正“可分配”;所有你真正能做的就是建立一个绑定,所以上面的代码就像这样说:

TL=[H3|TL]

这就是为什么我们的结果看起来像这样:L = ['F'| L]。我稍微重写了一下身体以解决问题并且使用了这段代码:

truth_list([H1|T1],[H2|T2],[H3|TL]):-
    (H1=H2 -> H3='T' ; H3='F'),
    truth_list(T1,T2,TL).

你需要在整个条件周围使用括号,否则你会得到奇怪的行为。从那里,我刚刚删除了不必要的TL绑定(它们无论如何都无法工作,因为Prolog中的变量不是可分配的)。事实证明,一旦你解决了这些问题,你会发现另一个问题,那就是你会得到这个:

L = ['F', 'T'|_G297].

如果不明显,这是因为你的基本情况太模糊了,应该是这样的:

truth_list([], [], []).

所以最终修正后的版本如下:

truth_list([],[],[]).
truth_list([H1|T1],[H2|T2],[H3|TL]):-
    (H1=H2 -> H3='T' ; H3='F'),
    truth_list(T1,T2,TL).

这通常是@false出现的地方,并指出我们在使用具有不同实例化的谓词时遇到问题,所以现在让我们检查一下并避免一些愤怒:

?- truth_list(['abc','def'],['zui','def'],['T','F']).
false.
?- truth_list(['abc','def'],['zui','def'],['F','T']).
true.
?- truth_list(['abc','def'],['zui','def'],['F','T','T']).
false.
?- truth_list(['abc','def'],['zui','def','def'],['F','T','T']).
false.

这些都看起来没问题,所以当所有参数都被实例化时,我们看起来并不是幻觉。非常好。现在让我们检查部分实例化:

?- truth_list([X, 'def'], ['abc', Y], ['T', 'T']).
X = abc,
Y = def.

很酷,这很有效。

?- truth_list([X, 'def'], ['abc', Y], ['F', 'T']).
false.

的Eh。好吧,看起来Prolog不知道为'F'值产生一些其他绑定。不确定这是否是一个问题,但我没有看到明显的解决方案。这意味着以下可能不起作用:

?- truth_list(X, Y, ['T', 'T']).
X = Y, Y = [_G296, _G302].

令人惊讶,但实际上确实有效,分配给两个未知数的同一个列表。凉。我认为我们状态很好。

编辑:让我们合并@ false的改进。然后我们得到以下内容:

truth_list([], [], []).
truth_list([H1|T1], [H2|T2], [H3|TL]) :-
  (H1 = H2, H3 = 'T' ; dif(H1,H2), H3 = 'F'),
  truth_list(T1, T2, TL).

现在我们得到了理想的行为:

?- truth_list([X, 'def'], ['abc', Y], ['F', 'T']).
Y = def,
dif(X, abc) ;

所以Prolog推断Y是'def',并得出结论X至少不是'abc',所以这是一个改进。

答案 1 :(得分:2)

maplist / 4可以简化您的代码:

truth_list(A, B, C) :-
  maplist(truth_, A, B, C).
truth_(A, B, C) :-
  A == B -> C = 'T' ; C = 'F'.

您还可以考虑增强(最终)重用的代码。

代替任意常量'T','F',您可以使用 callables 谓词,例如truefalse,或1,{{1}使用CLP(FD)

直接使用表达式