Reverse a List
№5 · 99 Picat ProblemsmyReverse(L) = myReverse(L, []).
myReverse([], R) = R.
myReverse([X|Xs], R) = myReverse(Xs, [X|R]).
Explanation
This function reverses a list using the accumulator pattern from Problem 4. Instead of counting elements, the accumulator builds the reversed list.
Wrapper function (line 1):
myReverse(L) = myReverse(L, []).
- Takes a single argument (the list) and calls a two-argument version with an empty list
[]as the initial accumulator - The accumulator will collect elements in reverse order
Base case (line 2):
myReverse([], R) = R.
- Pattern matches when the input list is empty
[] - Returns the accumulator
R, which now contains all elements in reverse order
Recursive case (line 3):
myReverse([X|Xs], R) = myReverse(Xs, [X|R]).
- Destructures the input list into head
Xand tailXs - Recurses on the tail, but prepends
Xto the accumulator with[X|R] - Each element is moved from the front of the input to the front of the accumulator, reversing the order
Note that Picat has a built-in reverse/1 function, so in practice you'd write reverse(L). The point here is to understand how the accumulator can build a result rather than just count.
Complete Example
Here's the full runnable code:
main =>
go_05.
go_05 =>
A = [1,2,3,4,5],
B = myReverse(A),
println(B).
myReverse(L) = myReverse(L, []).
myReverse([], R) = R.
myReverse([X|Xs], R) = myReverse(Xs, [X|R]).
How it works:
myReverse(A)calls the wrapper, which starts with an empty accumulator[]- Each recursive call moves one element from the input list to the front of the accumulator
println(B)outputs[5,4,3,2,1]
Example Execution
With A = [1,2,3,4,5]:
myReverse([1,2,3,4,5])
→ myReverse([1,2,3,4,5], []) (wrapper adds empty accumulator)
→ myReverse([2,3,4,5], [1]) (move 1 to accumulator)
→ myReverse([3,4,5], [2,1]) (move 2 to front of accumulator)
→ myReverse([4,5], [3,2,1]) (move 3 to front of accumulator)
→ myReverse([5], [4,3,2,1]) (move 4 to front of accumulator)
→ myReverse([], [5,4,3,2,1]) (move 5 to front of accumulator)
→ [5,4,3,2,1] (base case: input empty, return accumulator)
The reversal happens naturally: each element goes to the front of the accumulator, so the first element processed (1) ends up at the back, and the last element processed (5) ends up at the front.
Takeaways
- Accumulator as a builder: In Problem 4, the accumulator was a number that we incremented. Here it's a list that we build. Accumulators can carry any type of intermediate state.
- Prepending reverses order: By prepending each element to the accumulator with
[X|R], we naturally reverse the list. This is O(1) per element since prepending to a list is constant time. - Linear time reversal: This algorithm processes each element exactly once, making it O(n) where n is the length of the list.