我发现了一个类似的帖子,但它对我不起作用。所以请不要试图将我重定向到其他链接。
这是我想要的结果:
removeadj([a,a,a,b,c,c,a,a],[a,b,c,a]).
>True.
我试过这段代码:
concatener([],R,R).
concatener([X|Y],L,R):-concatener(Y,L,R1),R=[X|R1].
removeadj([],[]).
removeadj([X],[X]).
removeadj([X|Y],R):- Y=[X|L],removeadj(Y,R1),concatener([],R1,R).
removeadj([X|Y],R):- removeadj(Y,R1),concatener(X,R1,R).
当我尝试使用一个元素重复多次的列表时,它可以工作:
removeadj([a,a,a,a,a],[a]).
> True
但是当我使用不同的元素时,它不起作用:
removeadj([a,a,a,b],[a,b]).
> False.
我没有看到问题所在,所以我无法修复它。我需要你的帮助。
答案 0 :(得分:4)
首先是重新考虑你的关系的名称。目前,它表明有人必须做某事。 removeadj
这是一个命令。在编程语言中有足够的名称,其中命令是统治隐喻。但不是在Prolog中。
在Prolog,我们有关系。反映这种关系的名称通常非常有用。为什么不list_list/2
?毕竟,你的关系是两个列表!好吧,也许这个名字有点过于笼统。那么list__list_without_adjacent_elements/2
呢?冗长但有关系。也许我们将其缩短为:list_noadjs/2
。注意最后的s
:这意味着:它是复数,这意味着它是一个列表。
在考虑“做”这个或那个之前。而是冥想具体的例子 - 最好是地面的例子,就像你给他们的一样。以及其他属性。一个观察结果是第二个列表中的所有元素都将存在于第一个列表中。事实上不仅如此。但它们也会以相同的顺序出现。让我试着制定一下。当然,这种观察不足以编写整个谓词。但是这里的Prolog很酷:我们不需要实现一切。我们可以从包含我们想要的所有内容以及更多内容的粗略概括开始。
为了向您展示最极端,让我们试试:
list_noadjs(_Xs, _Ys).
这是所有二元关系的母亲!无论如何,这个定义总是成功的。显然,我们必须专注于它。比如说,通过查看列表的第二个参数:
list_noadjs(_Xs, []).
list_noadjs(_Xs, [Y|Ys]) :-
list_noadjs(_, Ys).
如果列表是[]
那么将是原始列表。两者都以相同的元素开始!
list_noadjs(Xs, []) :- Xs = []. list_noadjs(Xs, [Y|Ys]) :- Xs = [Y|_], list_noadjs(_, Ys).
或更紧凑:
list_noadjs([], []). list_noadjs([Y|_Xs], [Y|Ys]) :- list_noadjs(_, Ys).
现在,第一个列表包含第二个列表的元素。在其他事物之间:
list_noadjs([], []). list_noadjs([Y|Xs0], [Y|Ys]) :- list_(Xs0,Xs1), list_noadjs(Xs1, Ys). list_(Xs,Xs). list_([_|Xs0],Xs) :- list_(Xs0,Xs).
这已经是我们的关系吗?我们试一试:
| ?- list_noadjs("aaab",Ys).
Ys = "aaab" ? ;
Ys = "aaa" ? ;
Ys = "aab" ? ;
Ys = "aa" ? ;
Ys = "aab" ? ;
Ys = "aa" ? ;
Xs = "ab" ? ; % <===== * RRRIGHT !!!!***
Ys = "a" ? ;
no
(顺便说一下。我使用library(double_quotes)
来提高答案的可读性。)
所以我们确实有了预期的解决方案。唉,还有很多不正确的解决方案!我们将不得不继续专攻这个计划:
list_noadjs([], []).
list_noadjs([Y|Xs0], [Y|Ys]) :-
eq_list_(Y, Xs0,Xs1),
list_noadjs(Xs1, Ys).
eq_list_(_, Xs,Xs).
eq_list_(Y, [Y|Xs0],Xs) :-
eq_list_(Y, Xs0,Xs).
现在情况好多了,但仍然不完美:
| ?- list_noadjs("aaab",Ys).
Ys = "aaab" ? ;
Ys = "aab" ? ;
Ys = "aab" ? ;
Ys = "ab" ? ; % !!! Right
no
我们必须进一步专门化该程序:在一系列相同的元素之后,必须有其他东西:
list_noadjs([], []). list_noadjs([Y|Xs0], [Y|Ys]) :- eq_list_(Y, Xs0,Xs1), nohead(Xs1, Y), list_noadjs(Xs1, Ys). eq_list_(_, Xs,Xs). eq_list_(Y, [Y|Xs0],Xs) :- eq_list_(Y, Xs0,Xs). nohead([], _X). nohead([X|_], Y) :- dif(X, Y).
这就是我们的关系。
严重。不要只使用你拥有的测试用例。你现在有了关系!这不是伪装的功能,它确实不止于此。试试看!问完全不寻常的事情,比如:
| ?- list_noadjs(Xs,"abc").
Xs = "abc" ? ;
Xs = "abcc" ? ;
Xs = "abccc" ? ;
Xs = "abcccc" ...
所以我们在这里问:哪些列表对应"abc"
?请注意,只重复c
!所有其他解决方案都隐藏在这个无限的墙壁后面。但我们可以通过一些小技巧来获取它们:
| ?- length(Xs,N), list_noadjs(Xs,"abc").
Xs = "abc", N = 3 ? ;
Xs = "abcc", N = 4 ? ;
Xs = "abbc", N = 4 ? ;
Xs = "aabc", N = 4 ? ;
Xs = "abccc", N = 5 ? ;
Xs = "abbcc", N = 5 ? ;
Xs = "abbbc", N = 5 ? ;
Xs = "aabcc", N = 5 ? ;
Xs = "aabbc", N = 5 ? ;
Xs = "aaabc", N = 5 ? ;
Xs = "abcccc", N = 6 ? ...
我们已经看过:很多时候,我们会得到无数的解决方案。并且(我必须承认)更糟糕的是:有时,我们的关系甚至不会终止。
这是一个这样的例子。比方说,第二个参数中的列表是否包含重复项?或者说以下内容:
| ?- list_noadjs(Xs,[X,X]).
** LOOPS **
Prolog回答:嘟,,咕,,看见......
要掌握Prolog,您必须详细了解这一点。但目前,通常有一条好的出路:
所以不要问:是否任何术语可能与[X,X]
对应我们可能会问:是否有大小为5的列表(或任何其他有限大小)。现在Prolog否认了这一点:
| ?- Xs = [_,_,_,_,_] list_noadjs(Xs,[X,X]).
no
这不是你想要的普遍答案。但它总比没有好。
有时候所有这些查询对你来说都太过分了。让Prolog通过以下方式为您考虑:
通常,这很简单。从最常见的查询开始。这里的最大优点是根本不需要思考。而且你看起来像个专业人士:
| ?- list_noadjs(Xs,Ys).
Xs = [], Ys = [] ? ;
Xs = [_A], Ys = [_A] ? ;
Xs = [_A,_B], Ys = [_A,_B], dif(_B,_A) ? ;
Xs = [_A,_B,_C], Ys = [_A,_B,_C], dif(_B,_A), dif(_C,_B) ? ;
Xs = [_A,_B,_C,_D], Ys = [_A,_B,_C,_D], dif(_B,_A), dif(_C,_B), dif(_D,_C) ? ;
Xs = [_A,_B,_C,_D,_E], Ys = [_A,_B,_C,_D,_E], dif(_B,_A), dif(_C,_B), dif(_D,_C),
...
我们在这里得到的是所谓的答案。单个答案可能包含无限许多解决方案。想一想:你正在寻找无限!某些条件(称为约束)必须保持,例如dif/2
。但就是这样。
第三个答案是:
Xs = [_A,_B], Ys = [_A,_B], dif(_B,_A) ? ;
因此Xs
和Ys
是具有两个不同元素的相同列表。所以这个答案意味着Xs = "ab", Ys = "ab"
,但Xs = [1,2], Ys = [1,2]
还有很多甚至更多。
更好的是,以系统(“公平”)的方式列举所有答案:
| ?- length(Xs, N), list_noadjs(Xs,Ys).
Xs = [], N = 0, Ys = [] ? ;
Xs = [_A], N = 1, Ys = [_A] ? ;
Xs = [_A,_B], N = 2, Ys = [_A,_B], dif(_B,_A) ? ;
Xs = [_A,_A], N = 2, Ys = [_A] ? ;
Xs = [_A,_B,_C], N = 3, Ys = [_A,_B,_C], dif(_B,_A), dif(_C,_B) ? ;
Xs = [_A,_B,_B], N = 3, Ys = [_A,_B], dif(_B,_A) ? ;
Xs = [_A,_A,_B], N = 3, Ys = [_A,_B], dif(_B,_A) ? ;
Xs = [_A,_A,_A], N = 3, Ys = [_A] ? ;
Xs = [_A,_B,_C,_D], N = 4, Ys = [_A,_B,_C,_D], dif(_B,_A), dif(_C,_B), dif(_D,_C) ?
...
这些所有解决方案最长为3级。没有其他的!我们肯定知道这一点,因为最后的答案已经是4号了。所以下面的所有解决方案都已经在这里了!
经常看这些答案非常有帮助。例如,它允许您快速检测错误(如之前给出的其他答案)。所以,不要告诉任何人这个伎俩。
答案 1 :(得分:1)
谓词中的最后一个句子仍有问题:
removeadj([X|Y], [X|R1]):- removeadj(Y, R1).
如果X
后面的元素也是X
,则X
仍会在第二个参数的头部中携带。在允许第二个参数之前,此子句必须检查以下元素是否不同:
removeadj([X,Y|L], [X|R]) :-
dif(X,Y),
removeadj([Y|L], R).
此处,Y
仅在与X
不同的情况下位于第二个列表的开头。
所以整个解决方案看起来像:
removeadj([], []).
removeadj([X], [X]).
removeadj([X,X|T], R) :- % drop an X if next element is X
removeadj([X|T], R).
removeadj([X,Y|T], [X|R]) :- % carry X along if next element different
dif(X,Y),
removeadj([Y|T], R).
答案 2 :(得分:0)
removeadj([],[]).
removeadj([X],[X]).
removeadj([X|Y],R):- Y=[X|L],removeadj(Y,R1),R=R1.
removeadj([X|Y],[X|R1]):- removeadj(Y,R1).