及格
- 列表进阶
- 去括号
- 逻辑非
- 测试
- 平头哥
- 调试
- 交作业
- 很接近答案了
- 尝试
- 去掉老子
列表进阶
会了这题就可以及格了,原话如下:
Ok, we’re now halfway through the book. And flattening a list is the Pons Asinorum of Prolog programming. Did you cross it ok? If so, great. Time to move on.
去括号
?- flatten([a,b,[[[[[[[c,d]]]]]]],[[1,2]],foo,[]],Flat).
要得到
Flat = [a,b,c,d,1,2,foo]
看题目里面有一项是很多的括号[[[[[[[c,d]]]]]]],单从去括号来说应该没有那么难。那就一步一步来吧。
逻辑非
一直去到不能再去括号了,完成这句话就行了是吧。会用到逻辑编程填词游戏逻辑非的方法,学到后面也会专门讲的。代码如下:
islist([_]).
not(P) :- P, !, fail ; true.
flatten([X|[]],X):-
not(islist(X)).
flatten([X|[]],Y):-
flatten(X,Y).
可以看到递归调用的时候[X|[]]变成了X,就是这么简单!
测试
测试单个元组的多括号是可以去了。
?- flatten([[[[5]]]],X).
X=5
但是空还是返回了一个[]
?-flatten([[[[]]]],X).
无生万物,空先放一放直接往下走。
平头哥
是不是先这样处理列表的第一个元素,再递归处理后面的就搞定了。“|”,正好前面有学这个分割头尾符号。前面改成单平头flattentou,加两句。
flatten([X|TX],[Y|TY]):-
flattentou(X,Y),flatten(TX,TY).
直接返回false了
trace, (flatten([[[[5]]]],X)).
调试
Call:true
Exit:true
Exit:not(islist(5))
Exit:flattentou([5],5)
Exit:flattentou([[5]],5)
Exit:flattentou([[[5]]],5)
Call:flatten([],_1000)
到5 那里还是对的,加上老子吧,还是要考虑无生万物,参照逻辑的空无
flatten([],laozi).
调试后面加个老子,如下:
[5|laozi]
交作业
错了,这里做了很多尝试,发现原因是有些元组没有括号。
添加元组项不是列表的情况。直接加两行,吸收前面旅行的逻辑里并的做法。
flatten([X|TX],[X|TY]):-
flatten(TX,TY).
调试是又多走了很多的判断:
trace, (%flatten([a,b,[[[[[[[c,d]]]]]]],[[1,2]],foo,[]],X)
flatten([a,b],X)).
Call:flatten([a, b],_7288)
Call:flattentou(a,_1054)
Fail:flattentou(a,_1048)
Redo:flatten([a, b],_836)
Call:flatten([b],_1062)
Call:flattentou(b,_1060)
Fail:flattentou(b,_1054)
Redo:flatten([b],_1050)
Call:flatten([],_1068)
Exit:flatten([],laozi)
Exit:flatten([b],[b|laozi])
Exit:flatten([a, b],[a, b|laozi])
答案:
[a, b|laozi]还可以接受。
很接近答案了
[a, b, [c, d], [1, 2], foo, []|laozi] 1
[a, b, [c, d], [[1, 2]], foo, []|laozi] 2
[a, b, [[[[[[[c, d]]]]]]], [1, 2], foo, []|laozi] 3
[a, b, [[[[[[[c, d]]]]]]], [[1, 2]], foo, []|laozi]
看第一项里只有 [c, d], [1, 2]多了括号,多了空和老子,[]|laozi]。
尝试
最里层有多个的时候:
trace, (flatten([[[c,d]]],X)).
Call:flatten([[c, d]],_7294)
Call:flattentou([c, d],_1060)
Fail:flattentou([c, d],_1054)
Redo:flatten([[c, d]],_842)
Call:flatten([],_1068)
Exit:flatten([],laozi)
Exit:flatten([[c, d]],[[c, d]|laozi])
调试看是最后加的两行那里。
表头是一维列表的情况没有考虑。感觉就是只去一层中括号的情况,应该不难的吧。
是不是可以把‘|’改成‘,’逗号?
flattenone([X|TX],[X,Z]).
flattenone(TX,Z) .
trace, (flattenone([5,6],X)).
[5, _] 1
true
Redo:flattenone(’<garbage_collected>’,’<garbage_collected>’)
Exit:flattenone(’<garbage_collected>’,’<garbage_collected>’)
失败。
去掉老子
可以把laozi去掉了。
%flatten([],laozi). 这里改成空
全码:
islist([_]).
not(P) :- P, !, fail ; true.
flattentou([X|[]],X):-
not(islist(X)).
flattentou([X|[]],Y):-
flattentou(X,Y).%没有逗号,一个元素的情况
flattenone([],[]).
flattenone([X|TX],[X,Z]):-
flattenone(TX,Z) .
flatten([],[]). %这里改成空去掉老子
flatten([X|TX],[Y|TY]):-
flattentou(X,Y),flatten(TX,TY).
flatten([X|TX],[X|TY]):-
flatten(TX,TY).
% 多元素待完成
%flatten([[XX|TXX]|TX],[XX,TXX|TY]):-
% flattenone([XX|TXX],X),flatten(TX,TY).
![]() |
---|
谁会一不小心加这么多括号?也只有自己了。