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.
