Why is a Haskell List More Effective If It Left Associate

I learn the basics of Haskell and come across many tutorials saying that if the list is built from left to right using ++, it is more efficient than from right to left. But I can’t understand why.

For example, why this

a ++ (b ++ (c ++ (d ++ (e ++ f))))

more effective than

((((a ++ b) ++ c) ++ d) ++ e) ++ f
+4
source share
3 answers

It comes down to how lists and are implemented ++. You can think of implementing lists like

data List a = Empty | Cons a (List a)

[] Empty : Cons. Haskell. O(n), n . , , , , , , , .

, . a, b, c d n1, n2, n3 n4 ,

((a ++ b) ++ c) ++ d

a, a ++ b, x, n1, a n1 .

(x ++ c) ++ d

x, x ++ c, y n1 + n2 ( a b).

y ++ d

y , , n1 + n2 + n3, n1 + (n1 + n2) + (n1 + n2 + n3) = 3n1 + 2n2 + n3.

a ++ (b ++ (c ++ d))

, c ++ d -> x n3,

a ++ (b ++ x)

b ++ x -> y n2 ,

a ++ y

, , n1 n3 + n2 + n1, , 3n1 + 2n2 + n3.

+10

, . , .

Haskell , , , . , , , , . take 2 .

take 3 ([1] ++ ([2] ++ [3]))      vs.      take 3 (([1] ++ [2]) ++ [3])

, , . , , , . take (++)

take 0 _      = []
take n []     = []
take n (x:xs) = x : take (n-1) xs

[]     ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)

, n > 0, take n , (++) - .

take 3 ([1] ++ ([2] ++ [3]))
take 3 (1 : ([] ++ ([2] ++ [3])))
1 : take 2 ([] ++ ([2] ++ [3]))
1 : take 2 ([2] ++ [3])
1 : take 2 (2 : ([] ++ [3]))
1 : 2 : take 1 ([] ++ [3])        -- *
1 : 2 : take 1 [3]
1 : 2 : take 1 (3 : [])
1 : 2 : 3 : take 0 []
1 : 2 : 3 : []

, take (++), , .

. 3- . .

take 3 (([1] ++ [2]) ++ [3])
take 3 ((1 : ([] ++ [2])) ++ [3])
take 3 (1 : (([] ++ [2]) ++ [3]))
1 : take 2 (([] ++ [2]) ++ [3])     -- *
1 : take 2 ([2] ++ [3]
1 : take 2 (2 : ([] ++ [3]))
1 : 2 : take 1 ([] ++ [3])          -- *
1 : 2 : take 1 [3]
1 : 2 : take 1 (3 : [])
1 : 2 : 3 : take 0 []
1 : 2 : 3 : []

, take "", . (++). , . ([] ++ [2]) ++ [3], [] ++ ([2] ++ [3]), , LHS .

+10

:

a ++ (b ++ (c ++ (d ++ (e ++ f))))

a ++ b, a , , , - b a. ++ b ++ c, , , c ++ b ..

((((a ++ b) ++ c) ++ d) ++ e) ++ f

If you want to do ++ b ++ c, you first need to execute a ++ b and then add c to execute ++ b ++ C ++ d, you will have to do a ++ b again! then a ++ b ++ c, then add d.

Thus, in the second case there are many repeated calculations, therefore, it is slower.

0
source

Source: https://habr.com/ru/post/1542068/


All Articles