我需要过滤列表[#,d,e,#,f,g]
,以便获得输出,
每次遇到“#”时[[d,e],[f,g]]
,我都会在创建新列表时卡住,有没有办法做到这一点?
我尝试了下面的代码,
filterL([],List) :-[].
filterL([Head|Tail],X) :-
( Head \='#'->
append(X,Head,List),
filterL(Tail,List)
; filterL(Tail,X)
).
我需要过滤列表[#,d,e,#,f,g]
,以便获得输出,
每次遇到“#”时[[d,e],[f,g]]
,我都会在创建新列表时卡住,有没有办法做到这一点?
我尝试了下面的代码,
filterL([],List) :-[].
filterL([Head|Tail],X) :-
( Head \='#'->
append(X,Head,List),
filterL(Tail,List)
; filterL(Tail,X)
).
你的问题没有很好的定义。是否允许空序列?应[#]
与[[],[]]
(前后有一个空序列)或[]
?你说应该是[]
。所以:
list_splitbyhash(Xs, Xss) :-
phrase(splitby(Xss,#), Xs).
splitby([],_E) -->
[].
splitby(Xss,E) -->
[E],
splitby(Xss,E).
splitby([Xs|Xss],E) -->
{Xs = [_|_]},
all_seq(dif(E),Xs),
splitby(Xss,E).
all_seq(_, []) --> [].
all_seq(C_1, [C|Cs]) -->
[C],
{call(C_1,C)},
all_seq(C_1, Cs).
这是另一个版本,它使用了更通用的方法:
list_splitbyhash(Xs, Xss) :-
phrase(by_split(=(#), Xss), Xs).
=(X,X,true).
=(X,Y,false) :- dif(X,Y).
by_split(_C_2, []) --> [].
by_split(C_2, Xss) -->
[E],
{call(C_2,E,T)},
( { T = true },
by_split(C_2, Xss)
| { T = false, Xss = [[E|Xs]|Xss1] },
all_seq(callfalse(C_2),Xs),
el_or_nothing(C_2),
by_split(C_2, Xss1)
).
callfalse(C_2,E) :-
call(C_2,E,false).
el_or_nothing(_) -->
call(nil).
el_or_nothing(C_2), [E] -->
[E],
{call(C_2,E,true)}.
nil([], []).
使用lambdas可以更简洁地表达。代替
all_seq(callfalse(C_2),Xs)
和 的定义callfalse/3
,现在可以写
all_seq(C_2+\F^call(C_2,F,false))
有了元谓词splitlistIf/3
和具体化的相等谓词(=)/3
,手头的任务就变成了单行——既高效又逻辑纯!
?- splitlistIf(=(#),[#,d,e,#,f,g],Xs).
Xs = [[d,e],[f,g]]. % succeeds deterministically
由于代码是单调的,因此即使对于非常一般的查询也能确保逻辑上的健全性:
?- Xs = [A,B,C], splitlistIf(=(X),Xs,Yss).
Xs = [A,B,C], X=A , X=B , X=C , Yss = [ ] ;
Xs = [A,B,C], X=A , X=B , dif(X,C), Yss = [ [C]] ;
Xs = [A,B,C], X=A , dif(X,B), X=C , Yss = [ [B] ] ;
Xs = [A,B,C], X=A , dif(X,B), dif(X,C), Yss = [ [B,C]] ;
Xs = [A,B,C], dif(X,A), X=B , X=C , Yss = [[A] ] ;
Xs = [A,B,C], dif(X,A), X=B , dif(X,C), Yss = [[A],[C]] ;
Xs = [A,B,C], dif(X,A), dif(X,B), X=C , Yss = [[A,B] ] ;
Xs = [A,B,C], dif(X,A), dif(X,B), dif(X,C), Yss = [[A,B,C]].