While I was reading chapter 13 from Real World Haskell
i came upon the concept of Difference Lists
.
The author says that in an imperative language if we want to append an element to a list, the cost would be O(1)
since we would keep a pointer to the last element.
However in Haskell, we have immutable
objects so we would need every time to traverse the list and append the element at the end, thus 0(n)
.
Instead of [1,2,3]++[4]++[5]
we could use partial application: (++4).(++5) [1,2,3]
.
I do not understand how is this more efficient since:
- when i do (++[5]) [1,2,3]
it would still be O(n)
and then another 0(n)
for (++4)
Quote
There are two very interesting things about this approach. The first is that the cost of a partial application is constant, so the cost of many partial applications is linear. The second is that when we finally provide a [] value to
unlock the final list from its chain of partial applications, application
proceeds from right to left. This keeps the left operand of (++) small, and so
the overall cost of all of these appends is linear, not quadratic
I understand that this approach would be eager, so instead of keeping thunks of yet to be applied methods
we keep the left operand small
as the author says, but .... we still perform a traverse on each append.
Given a list: [1...100]
and wanting to append 1,2
i would still traverse it 2
times since I would :
f(f([1..100]))= f([1..100,1])
- traversed 1 time and appended1
[1..100,1,2]
-traversed the second time to append2
Can someone illuminate me on how is this more efficient in time complexity? (becausespace
-complexity is due to no more thunks
, like foldl'
)
P.S
I am aware of the canonical answer and I have also read this chapter which I found very helpful.
I know that you can achieve O(1)
complexity by appending to the left using :
, but it wouldn't be similar to ++
.
If i use f=(:)
on a= [1,2,3]
:
(f 4 . f 5) $ a
I could say that i had 0(1)
efficiency on each append since i always appended on the to the left , but i would not get [1,2,3,4,5]
, i would get [5,4,1,2,3]
, so how is in this case a difference list
more efficient for the unitary operation of appending one element ?