Find the Number of Elements of a List
№4 · 99 Picat ProblemsmyLength(L) = myLength(L, 0).
myLength([], Len) = Len.
myLength([_|Xs], Len) = myLength(Xs, Len+1).
Explanation
This function counts the number of elements in a list. Unlike the previous problems that peeled off elements until reaching a stopping condition, this one introduces a new pattern: the accumulator.
Wrapper function (line 1):
myLength(L) = myLength(L, 0).
- Takes a single argument (the list) and calls a two-argument version with
0as the initial count - This gives callers a clean interface - they don't need to know about the internal accumulator
Base case (line 2):
myLength([], Len) = Len.
- Pattern matches when the list is empty
[] - Returns the accumulated count
Len - When we've consumed every element, the accumulator holds the final answer
Recursive case (line 3):
myLength([_|Xs], Len) = myLength(Xs, Len+1).
- Uses the same
[Head|Tail]destructuring as Problem 1 - Ignores the head with
_- we only care that an element exists, not what it is - Recurses on the tail
XswithLen+1, incrementing the count for each element
Note that Picat has a built-in length/1 function, so in practice you'd write length(L). The point here is to understand how accumulator-based recursion works.
Complete Example
Here's the full runnable code:
main =>
go_04.
go_04 =>
A = [1,2,3,4,5],
B = myLength(A),
println(B).
myLength(L) = myLength(L, 0).
myLength([], Len) = Len.
myLength([_|Xs], Len) = myLength(Xs, Len+1).
How it works:
myLength(A)calls the wrapper, which starts the count at0- Each recursive call strips one element and adds
1to the accumulator println(B)outputs5(the list has five elements)
Example Execution
With A = [1,2,3,4,5]:
myLength([1,2,3,4,5])
→ myLength([1,2,3,4,5], 0) (wrapper adds initial accumulator)
→ myLength([2,3,4,5], 1) (ignore 1, increment count)
→ myLength([3,4,5], 2) (ignore 2, increment count)
→ myLength([4,5], 3) (ignore 3, increment count)
→ myLength([5], 4) (ignore 4, increment count)
→ myLength([], 5) (ignore 5, increment count)
→ 5 (base case: empty list, return accumulator)
The accumulator carries the running total forward through each recursive call. When the list is empty, the accumulator holds the final count.
Takeaways
- Accumulator pattern: A wrapper function initializes an extra parameter that carries state through the recursion. The wrapper gives callers a clean single-argument interface while the helper does the real work with the extra parameter.
- Empty list as base case: Previous problems stopped at one or two elements. Here the base case is
[]because we need to count every element, including the last one. - Tail recursion: The recursive call
myLength(Xs, Len+1)is the last operation - there's nothing left to do after it returns. This is called tail recursion, and Picat can optimize it to avoid growing the call stack.