views:

42

answers:

2

I am writing a prolog program to solve a problem. The problem takes three lists as input:

  solve( [L|Lr] , [R|Rr] , [S|Sr] ) :-

Unfortunately the lists all need to be equal length for the program to work.

So these work:

?- solve( [A, B, C, D] , [1, 3, 5, 6], [E, F, G, H]).
?- solve( [1] , [2], [3]).

But these do not:

?- solve( [A, B, C, D], [1], [B, I, T] ).
?- solve( [A], [1, 2], [4, 5]).

What I would like to do is write a predicate(?) to pad the smaller lists with leading zeros. So:

solve( [A, B, C, D], [1], [B, I, T] ) 

would become:

solve( [A, B, C, D], [0, 0, 0, 1], [0, B, I, T] )

Any points on how to accomplish this would be awesome. I am from a functional background so I am struggling. Is there a way tell the length of a list? I think I could do that recursively, but it seems like a pain.

Thanks

+1  A: 

The length(List, Length) predicate is used to get the length of a list. I did a small program that put the leading zeros into a list.

addZeros(L, 0, L).
addZeros(L, 1, [0|L]).
addZeros(L, N, [0|FL]) :-
        N2 is N - 1,
        addZeros(L, N2, FL).

compZeros(_, 0, []).
compZeros(L, N, FL) :-
        length(L, S),
        S < N,
        N2 is N - S,
        addZeros(L, N2, FL).
compZeros(L, _, L).

Just pass the list and the size of the final list.

?- compZeros([1], 4, L).
L = [0, 0, 0, 1] 

?- compZeros([1, 2, 3], 4, L).
L = [0, 1, 2, 3] 

?- compZeros([1, 2, 3, 4], 4, L).
L = [1, 2, 3, 4].
Ed
Brilliant, thanks ed, I was having a hard time conceptualizing that. However I think that your second base case for add zeros is redundant.
sixtyfootersdude
A: 

Yet another variant with using only unification.

padZerosPrep(L, [], L).
padZerosPrep(L, [_|T], [0|R]):- padZerosPrep(L, T, R).

padZerosWalk([], [], La, Lb, La, Lb).
padZerosWalk([], [_|_], La, Lb, La, Lb).
padZerosWalk([_|_], [], La, Lb, La, Lb).
padZerosWalk([_|La0], [_|Lb0], [_|La1], [_|Lb1], La, Lb):-
    padZerosWalk(La0, Lb0, La1, Lb1, La, Lb).

padZeros(La0, Lb0, La, Lb):-
    padZerosPrep(La0, Lb0, La1),
    padZerosPrep(Lb0, La0, Lb1),
    padZerosWalk(La0, Lb0, La1, Lb1, La, Lb).

Just pass two lists and remember that second pair of list will have the same length:

?- padZeros([1,2,3],[4,5,6],A,B).
A = [1, 2, 3],
B = [4, 5, 6]

?- padZeros([1,2,3],[4,5],A,B).
A = [1, 2, 3],
B = [0, 4, 5]

?- padZeros([2,3],[4,5,6],A,B).
A = [0, 2, 3],
B = [4, 5, 6]

?- La=[A,B,C,D], Lb = [1], Lc=[B,I,T], padZeros(La, Lb, La1, Lb1), padZeros(La1, Lc, La2, Lc2), padZeros(Lb1, Lc, Lb2, Lc2).
La = [A, B, C, D],
Lb = [1],
Lc = [B, I, T],
La1 = [A, B, C, D],
Lb1 = [0, 0, 0, 1],
La2 = [A, B, C, D],
Lc2 = [0, B, I, T],
Lb2 = [0, 0, 0, 1]

?- Lc=[A,B,C,D], Lb = [1], La=[B,I,T], padZeros(La, Lb, La1, Lb1), padZeros(La1, Lc, La2, Lc2), padZeros(Lb1, Lc, Lb2, Lc2).
Lc = [A, B, C, D],
Lb = [1],
La = [B, I, T],
La1 = [B, I, T],
Lb1 = [0, 0, 1],
La2 = [0, B, I, T],
Lc2 = [A, B, C, D],
Lb2 = [0, 0, 0, 1]

P.S. Don't try those predicates in reverse variant.
Same variant in Haskell:

padZeros :: (Num a, Num b) => [a] -> [b] -> ([a], [b])
padZeros a b = walk (zip a b) pa pb where
    pa = map (const 0) b ++ a
    pb = map (const 0) a ++ b
    walk [] a' b' = (a', b')
    walk (_:xs) (_:a') (_:b') = walk xs a' b'
ony