如何实现按第一个列表元素个数复制第二个列表的Prolog谓词?
times/3 Predicate Let's break down why your original code isn't working, then walk through a correct implementation that does exactly what you need.
What's Wrong With the Original Code?
Your current code has a key issue with variable binding and result accumulation:
times( [ ], _, [ ] ) :- !. times( [ _ | List1 ], List2, Result ) :- append( [], List2, Result ), % This binds Result directly to List2 times( List1, List2, Result ). % Now you're trying to re-bind Result in recursion
When you call append([], List2, Result), you're immediately setting Result equal to List2. Then, when you recurse, you pass the same Result variable—Prolog can't change its value, so the recursion just keeps reaffirming Result = List2 instead of building up the repeated list. That's why you never get the duplicated list you expect.
Correct Implementation Options
Option 1: Tail-Recursive with Accumulator (Efficient)
Tail recursion is better for performance in Prolog, as it avoids building up a stack of recursive calls. We'll use an accumulator to build our result step by step:
% Public predicate: start with empty accumulator times(List1, List2, Result) :- times_acc(List1, List2, [], Result). % Base case: when List1 is empty, return the accumulated result times_acc([], _, Accumulator, Accumulator). % Recursive case: append List2 to the accumulator, then recurse on the rest of List1 times_acc([_ | Rest], List2, Accumulator, Result) :- append(Accumulator, List2, NewAccumulator), times_acc(Rest, List2, NewAccumulator, Result).
Option 2: Simple Recursion (More Readable for Beginners)
If you prefer a more straightforward recursive approach without an accumulator, this works too:
% Base case: empty input list gives empty result times([], _, []). % Recursive case: first get the result of repeating List2 for the rest of List1, % then prepend List2 to that sub-result times([_ | Rest], List2, Result) :- times(Rest, List2, SubResult), append(List2, SubResult, Result).
Testing It Out
When you call times([x, x], [1, 5, 9, 8], Result), both implementations will correctly unify Result with [1, 5, 9, 8, 1, 5, 9, 8].
Let's trace the simple recursion version to see how it works:
times([x, x], [1,5,9,8], R)callstimes([x], [1,5,9,8], SubR)times([x], [1,5,9,8], SubR)callstimes([], [1,5,9,8], SubSubR)times([], ..., SubSubR)unifiesSubSubRwith[]- Back to the second call:
append([1,5,9,8], [], SubR)→SubR = [1,5,9,8] - Back to the first call:
append([1,5,9,8], [1,5,9,8], R)→R = [1,5,9,8,1,5,9,8]
内容的提问来源于stack exchange,提问作者adi pslr

