Prolog 序言:如何使三个列表的长度相同(通过添加前导零)

Prolog 序言:如何使三个列表的长度相同(通过添加前导零),prolog,Prolog,我正在写一个Prolog程序来解决一个问题。该问题以三个列表作为输入: solve( [L|Lr] , [R|Rr] , [S|Sr] ) :- 不幸的是,列表的长度必须相等,程序才能工作 因此,这些工作: ?- solve( [A, B, C, D] , [1, 3, 5, 6], [E, F, G, H]). ?- solve( [1] , [2], [3]). 但这些并不是: ?- solve( [A, B, C, D], [1], [B, I, T] ). ?- solve( [

我正在写一个Prolog程序来解决一个问题。该问题以三个列表作为输入:

  solve( [L|Lr] , [R|Rr] , [S|Sr] ) :-
不幸的是,列表的长度必须相等,程序才能工作

因此,这些工作:

?- solve( [A, B, C, D] , [1, 3, 5, 6], [E, F, G, H]).
?- solve( [1] , [2], [3]).
但这些并不是:

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

我想做的是写一个谓词(?)用前导零填充较小的列表。因此:

solve( [A, B, C, D], [1], [B, I, T] ) 
将成为:

solve( [A, B, C, D], [0, 0, 0, 1], [0, B, I, T] )
关于如何实现这一点的任何观点都将非常棒。我来自功能性背景,所以我很努力。有没有办法说出一张清单的长度?我想我可以反复这么做,但这似乎很痛苦

长度(List,length)谓词用于获取列表的长度。我做了一个小程序,将前导零放入一个列表中

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).

另一个仅使用统一的变体

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).
只需传递两个列表,并记住第二对列表将具有相同的长度:

?- 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]
注意,不要用反向变体尝试这些谓词。
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'

太棒了,谢谢你,ed,我当时很难理解这一点。然而,我认为你的第二个基本情况下添加零是多余的。
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'