Reputation: 25
I have tried to write a rule that checks if a list is a chain like:
[[5,2],[2,4]] - true
[[7,2],[4,0]] - false
[[1,2]] - false, single element lists are not chains too.
So, pattern is like [[a,b], [b,c], [c,d], ...]
(inner lists always contain two elements and any of a, b, c, d... might be equal).
chain([]):-!.
chain([X]):-false.
chain([_|[]]):-!.
chain([[_, X2]|[[Y1, Y2]|Tail]]):-
X2 == Y1,
chain([[Y1, Y2]|Tail]).
With
-? chain([[1,2]]).
I got true, which confuses me.
Also I've tried to replace second line with chain(L):-length(L, Len),Len>1.
, but the result remains the same.
I appreciate any help and explanation.
Upvotes: 1
Views: 75
Reputation: 2422
There is no need to explicitly fail. Just don't write a rule for that case, the rule will then fail because it can't succeed.
Here is one way to do it:
chain([[_,X],[X,Y]|Rest]) :-
chain_1(Rest, Y).
chain_1([], _).
chain_1([[X,Y]|Rest], X) :-
chain_1(Rest, Y).
Does that work for all your corner cases?
There is very little to explain here. If something isn't obvious ask specific questions.
Because there is a certain obsession with the most general query around these parts, and I am a natural crowd pleaser, I will do as the Romans do:
?- chain(X).
X = [[_, _A], [_A, _]] ;
X = [[_, _A], [_A, _B], [_B, _]] ;
X = [[_, _A], [_A, _B], [_B, _C], [_C, _]] ;
X = [[_, _A], [_A, _B], [_B, _C], [_C, _D], [_D, _]] .
Cool!
Since chain_1/2 is a left fold on the list, you could write this as:
chain([[_,X],[X,Y]|Rest]) :-
foldl(chain_rule, Rest, Y, _).
chain_rule([X,Y], X, Y).
Doesn't get more readable but you can show off to your friends.
Upvotes: 2