I would like to split a list of words separated through integers into a list of lists.
Sample query and expected result:
?- separatewords([h,e,l,l,o,1,o,v,e,r,3,t,h,e,r,e], X).
X = [[h,e,l,l,o],[o,v,e,r],[t,h,e,r,e]].
The following things I already achieved:
Splitting the list into one list before the first integer and one after the first integer:
Sample query with result:
?- take1word([h,e,l,l,o,1,o,v,e,r,3,t,h,e,r,e], X, Y).
X = [h,e,l,l,o], Y = [o,v,e,r,3,t,h,e,r,e]. % OK
My code:
take1word([H|T],[],T) :-
integer(H).
take1word([H|T],[H|Hs],Y) :-
( float(H), take1word(T,Hs,Y)
; atom(H), take1word(T,Hs,Y)
).
For separating words my code is the following:
separatewords([],[]).
separatewords([H|T],L) :- separatewords(T,[take1word([H|T],)|L]).
It only give me false
as a result, but I don't know, what I am doing wrong.
You have an issue with take1word/3
: it will take a word if there is an integer in the list, but it will not take the last word. You need to add another base clause to it:
take1word([], [], []).
take1word([H|T],[],T) :- integer(H).
take1word([H|T],[H|Hs],Y) :- float(H), take1word(T,Hs,Y); atom(H), take1word(T,Hs,Y).
Now your separatewords/2
will work:
separatewords([],[]).
separatewords(L, [W|T]) :- take1word(L,W,R), separatewords(R,T).
Demo.
Here is how you could proceed in a logically-pure fashion.
Use meta-predicate splitlistIf/3
in tandem with the reified type test predicate integer_t/2
!
integer_t(X,Truth) :- integer(X), !, Truth = true.
integer_t(X,Truth) :- nonvar(X), !, Truth = false.
integer_t(X,true) :- freeze(X, integer(X)).
integer_t(X,false) :- freeze(X,\+integer(X)).
Let's see them both in action!
?- Xs=[ h,e,l,l,o,1,o,v,e,r,3,t,h,e,r,e ], splitlistIf(integer_truth,Xs,Yss).
Xs = [ h,e,l,l,o,1,o,v,e,r,3,t,h,e,r,e ],
Yss = [[h,e,l,l,o],[o,v,e,r],[t,h,e,r,e]]. % succeeds deterministically
As the implementation is monotone, it can be safely used when we work with non-ground terms.
Consider the following two logically equivalent queries: Procedurally, they differ regarding the instantiation of items in Xs
at the time the goal splitListIf(integer_t,Xs,Yss)
is proven.
?- Xs = [_,_,_,_,_], Xs = [a,b,0,b,a], splitlistIf(integer_t,Xs,Yss).
Xs = [a,b,0,b,a], Yss = [[a,b],[b,a]]. % succeeds deterministically
?- Xs = [_,_,_,_,_], splitlistIf(integer_t,Xs,Yss), Xs = [a,b,0,b,a].
Xs = [a,b,0,b,a], Yss = [[a,b],[b,a]] % succeeds leaving behind choicepoint
; false.
The implementation is smart enough to leave behind choicepoint(s) only when necessary.