我真的很抱歉以前的问题,这是我第一次在这个网站上发帖提问,我真的不知道我不应该发布这样的问题。 这是我第一次使用prolog。实际上我在这个问题上花了5个多小时但仍然不能完全解决它,我试图将这个问题拆开,这里还有待解决的问题:
如何将连续增加的整数放入原始列表中的子列表中。
例如。 [3,5,1,2,3,7,8,2]至[3,5,[1,2,3],[7,8],2]
以下是我写的内容,有人可以告诉我如何修复代码吗?感谢。
{{1}}
答案 0 :(得分:3)
感谢您更新问题以向我们展示您的尝试!
像所有Prolog初学者一样,你想要立刻做太多。这个是正常的!但是你必须学习并习惯一种与其他编程语言不同的思维方式。几乎总是你必须将你的问题分解成几个子问题,然后将它们放在一起以获得最终的程序。
因此,让我们首先尝试解决问题的一部分:给定一个非空列表,将其分解为前面的连续元素和所有剩余元素。也就是说,我们想要这样的东西:
?- list_successive_rest([1, 2, 4, 3], Succ, Rest).
Succ = [1, 2],
Rest = [4, 3] .
如果我们可以编写此定义,那么我们应该能够遍历Rest
以进一步切割它。
以下是list_successive_rest/3
的定义。请注意它是如何遵循chop_up/2
尝试的结构,但它更短更简单,因为我们只查看列表的连续前缀,而不是一次查看所有列表:
list_successive_rest([X], [X], []).
list_successive_rest([A, B | Xs], [A], [B | Xs]) :-
A + 1 =\= B.
list_successive_rest([A, B | Xs], [A | Successive], Rest) :-
A + 1 =:= B,
list_successive_rest([B | Xs], Successive, Rest).
(这也比你的版本简单,因为我将至少两个元素的列表与[A, B | Xs]
而不是[A | Tail]
和Tail = [B | Tail2]
匹配。习惯这种语法是个好主意。)
我们可以连续调用它来将列表分解为连续的部分:
?- list_successive_rest([1, 2, 4, 3], Succ, Rest), list_successive_rest(Rest, Succ2, Rest2), list_successive_rest(Rest2, Succ3, Rest3).
Succ = [1, 2],
Rest = [4, 3],
Succ2 = [4],
Rest2 = Succ3, Succ3 = [3],
Rest3 = [] ;
false.
使用上面的谓词迭代地剥离列表的连续前缀,现在可以很容易地定义chop_up/2
:
chop_up([], []).
chop_up(List, [Succ | Chopped]) :-
list_successive_rest(List, Succ, Rest),
chop_up(Rest, Chopped).
请注意chop_up/2
是递归的,它使用list_successive_rest/3
,它也是递归的。试图在一个递归谓词中写下所有这些内容会更难,导致代码可读性降低。
让我们尝试上面的测试和你的测试用例:
?- chop_up([1, 2, 4, 3], Chopped).
Chopped = [[1, 2], [4], [3]] ;
false.
?- chop_up([3,5,1,2,3,7,8,2], Chopped).
Chopped = [[3], [5], [1, 2, 3], [7, 8], [2]] ;
false.
这实际上并不会产生您想要的确切格式:Singleton元素是单例列表而不是外部列表的“裸”成员。我认为这种方式更好,但你的老师可能不同意。在这种情况下,更改这个小细节是一项练习。
答案 1 :(得分:3)
我用DCG提出了更优雅的方式!
chunk_list([])-->[].
chunk_list([C|Rest])-->chunk(C),chunk_list(Rest).
chunk(Ret)-->[First],consecutive(First,Last),{First=:=Last->Ret is First;Ret = [First,Last]}.
consecutive(Prev,Last)-->[Current],{Current is Prev+1},consecutive(Current,Last).
consecutive(Prev,Prev)-->[].
测试:
?- phrase(chunk_list(R),[1,2,3,6,7,3,3,2,3,4,6],[]).
R = [[1, 3], [6, 7], 3, 3, [2, 4], 6]
也许它可以在更多的时候可以逆转。
I.E.将[[1,3],[6,7],3,3,[2,4],6]转换为[1,2,3,6,7,3,3,2,3,4,6]
答案 2 :(得分:1)
我也尝试过我的prolog培训。
可怕的计划,但无论如何确实有效。
我在ECLiPSe中对此进行了测试,但在其他环境中进行了少量修改(可能只是删除了:-lib(listut)
)
这样打电话:
chunk([4,5,6,3,4,4,57,3,4,5,7,2,3,4,5,7,7,54,3],Ret).
程序:
:-lib(listut).
chunk(List,Ans):-
chunk_sub(List,0,[],List1),
first_and_lasts(List1,Ans),
!.
chunk_sub([],_,Ret,Reverse):-reverse(Ret,Reverse),!.
chunk_sub([Current|Rest],Prev,[NowList|RetRest],Ret):-
Current =:= Prev+1,
append(NowList,[Current],NextList),
chunk_sub(Rest,Current,[NextList|RetRest],Ret).
chunk_sub([Current|Rest],_,NowList,Ret):-
chunk_sub(Rest,Current,[[Current]|NowList],Ret).
first_and_lasts([],[]):-!.
first_and_lasts([FirstList|RestLists],[Converted|RestRet]):-
length(FirstList,Len),
(
Len=:=1->
([OneElem]=FirstList,Converted=OneElem);
(
nth1(1,FirstList,Smallest),
nth1(Len,FirstList,Biggest),
Converted=[Smallest,Biggest]
)
),
first_and_lasts(RestLists,RestRet).
答案 3 :(得分:1)
最后我做到了! 这是可逆的(通用)版本。这个程序巧妙地工作。 发展这个非常有趣。
代码:
chunk_list([])-->[],!.
chunk_list([Chunk|Rest])-->chunk(Chunk),!,chunk_list(Rest).
chunk([First,Last])-->sequence([First,Last]),{First<Last}. % sequence
chunk(Val)-->sequence([Val,Val]). % isolated number
sequence([First,Last])-->
{(number(First),number(Last))->First<Last;true},
[First],
{succ(First,Second)},sequence([Second,Last]).
sequence([Val,Val])-->[Val].
测试:
[eclipse 4]: phrase(chunk_list([2,[2,6],[3,5],3,7,[1,3]]),Ret).
Ret = [2, 2, 3, 4, 5, 6, 3, 4, 5, 3, 7, 1, 2, 3]
Yes (0.00s cpu)
[eclipse 5]: phrase(chunk_list(Ret),[3,4,5,2,1,6,7,88,9,4,5,6,7,2,1,2,3]).
Ret = [[3, 5], 2, 1, [6, 7], 88, 9, [4, 7], 2, [1, 3]]
Yes (0.00s cpu)
[eclipse 6]: phrase(chunk_list([[2,4],A,[2,8],3]),[2,B,4,6,2,C,4,5,6,7,D,E]).
A = 6
B = 3
C = 3
D = 8
E = 3
Yes (0.00s cpu)