2

我写了一些 Prolog 来用一个原子替换列表二中的元素,empty如果它们包含在列表一中:

replace_build([], _Inv, _Res).

replace_build([A| B], Inv, Res) :-
    replace_build2(A, Inv, Res), replace_build(B, Inv, Res).

replace_build2(_BuildItem, [], _NewInv) :- !.

replace_build2(BuildItem, [BuildItem| T], NewInv) :-
    replace_build2(BuildItem, T, NewInv1),
    append([empty], NewInv1, NewInv).

replace_build2(BuildItem, [H| T], NewInv) :-
    replace_build2(BuildItem, T, NewInv1),
    append([H], NewInv1, NewInv).

但是,当我运行它时,根据以下示例,我得到一个不寻常的匿名变量(这是正确的术语吗?):

?- replace_build([item3], [empty, item5, item1, item3, empty], X).
X = [empty, item5, item1, empty, empty|_G467]

(它也满足了我不想要的,尽管希望我能解决这个问题!)

为什么|_G467在结果列表中?

4

2 回答 2

2

问题一是这个条款:

replace_build2(_BuildItem, [], _NewInv) :- !.

您可以通过放置一个[]for来修复它_NewInv

replace_build2(_BuildItem, [], []) :- !.

问题只是你有一个未实例化的变量被附加到:

?- replace_build([item3], [empty, item5, item1, item3, empty], X).
X = [empty, item5, item1, empty, empty] ;
X = [empty, item5, item1, item3, empty].

你有两个答案的原因是因为replace_build2匹配的第二个子句,这就是你得到emptyitem3在那里的原因。Prolog 很乐意将两个变量统一为相同的值,这里没有什么可以停止BuildItemH引用相同的值。您需要明确告诉 Prolog 这些是不同的,因此将您的最后一个replace_build2子句更改为:

replace_build2(BuildItem, [H| T], NewInv) :-
  BuildItem \= H,
  replace_build2(BuildItem, T, NewInv1),
  append([H], NewInv1, NewInv).

现在你只得到你想要的解决方案:

?- replace_build([item3], [empty, item5, item1, item3, empty], X).
X = [empty, item5, item1, empty, empty] ;
false.

你也可以dif/2在一些 Prologs 中使用。

于 2013-03-26T14:55:39.490 回答
2

当您有一个“列表转换”任务时,需要处理一个“项目一次”逻辑,您可以使用maplist /N。

然后

replace_build(Items, Inv, Res) :-
    maplist(replace_build_item(Inv), Items, Res).

replace_build_item(Inv, Item, Res) :-
    memberchk(Item, Inv) -> Res = empty ; Res = Item.

但是要学习 Prolog,你就走在了正确的轨道上,Daniel 很好地解释了你的问题。掌握基本的列表处理任务很重要!

于 2013-03-26T18:01:11.453 回答