Example
In the same way that length/2 can generate lists of fresh unbound variables:
?- length(L,3). L = [_22942, _22948, _22954].
so can same_length/2
?- same_length(L,[0,1,2,3,4]). L = [_7972, _7978, _7984, _7990, _7996]. ?- same_length([0,1,2,3,4],R). R = [_8914, _8920, _8926, _8932, _8938].
Non-determinism if both arguments are unbound variables:
?- same_length(L,R). L = R, R = [] ; L = [_10602], R = [_10608] ; L = [_10602, _11640], R = [_10608, _11646] ; L = [_10602, _11640, _12678], R = [_10608, _11646, _12684] ...
Also works with "open lists" (i.e. lists which have an unbound variable as the "fin" (2nd argument of the last listcell of the backbone, my terminology)):
?- same_length([1,2|X],[2,4|Y]). X = Y, Y = [] ; X = [_8562], Y = [_8568] ; X = [_8562, _9696], Y = [_8568, _9702] . ?- same_length([1,2|X],[2,4|X]). X = [] ; X = [_12618] ; X = [_12618, _13354] ; X = [_12618, _13354, _14090]
Missed opportunity / see also
There should be a
which also takes the length. This helps to avoid having to immediately call length/2 in some generative cases. Very useful!
You can set one up using foldl/5 and a library(yall) expression:
same_length(L1,L2,LL) :- foldl({LL}/[_,_,FL,TR]>>(succ(FL,TR),(nonvar(LL) -> TR=<LL ; true)),L1,L2,0,LL).
There actually is one in the the SICStus compatibility library. The difference with the above is that the above fails if given a negative length, but the SICStus one throws.
Test code for SICStus version:
:- use_module(library('dialect/sicstus/lists.pl')). :- begin_tests(same_length_3). test(1) :- same_length(List,[a,b,c],Length), assertion(is_list(List)), assertion(Length==3). test(2) :- same_length([a,b,c],List,Length), assertion(is_list(List)), assertion(Length==3). test(3) :- same_length([a,b,c],[1,2,3],Length), assertion(Length==3). test(4,fail) :- same_length([a,b],[1,2,3],_). test(5) :- bagof(solution(List1,List2),same_length(List1,List2,3),Bag), assertion(Bag = [solution([_,_,_],[_,_,_])]). test(6) :- bagof(solution(List1,List2,Length),limit(4,same_length(List1,List2,Length)),Bag), assertion(Bag = [solution([], [], 0), solution([_], [_], 1), solution([_,_], [_,_], 2), solution([_,_,_], [_,_,_], 3)]). test(7) :- same_length([a,b,c,d,e],[1,2|Rest],Length), assertion(Rest = [_,_,_]), assertion(Length = 5). /* test(9,fail) :- same_length(_List1,_List2,-1). */ test(9,[error(domain_error(_,_))]) :- same_length(_List1,_List2,-1). test(10,nondet) :- same_length(List1,List2,0), assertion(List1 = []), assertion(List2 = []). :- end_tests(same_length_3).
Run the above with
?- run_tests.
as usual.