Anton Potapov
Anton Potapov

Reputation: 25

Unexpected result of the rule

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

Answers (1)

TA_intern
TA_intern

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

Related Questions