Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell List Concatenation vs. (head : tail) format

Tags:

list

haskell

I always wrote my list-producing recursive functions in this format:

recursiveFunc :: [a] -> [b]
recursiveFunc (x:xs) = [change x] ++ resursiveFunc xs where
    change :: a -> b
    change x = ...

I realize any function like the above could be written for the a -> b case and then simply maped over a set [a], but please take this watered-down situation as an example.

HLint suggests replacing [change x] ++ recursiveFunc xs with change x : recursiveFunc xs.

Is this suggestion purely aesthetic, or is there some effect on how Haskell executes the function?

like image 790
Xander Dunn Avatar asked Mar 01 '12 16:03

Xander Dunn


3 Answers

When using [change x] ++ recursiveFunc xs you create a superfluous one-element list, which is then taken apart by the ++ function. Using : that doesn't happen.

Plus ++ is a function which then will use the : constructor. When you use : directly, there's no need to invoke a function.

So using : is more efficient in theory (the compiler might optimize those differences away, though).

like image 195
sepp2k Avatar answered Nov 05 '22 18:11

sepp2k


The line

recursiveFunc (x:xs) = [change x] ++ resursiveFunc xs

is a bit confusing since it is not in normalform. That means that ++ can be replaced directly with one right hand side of its definition:

(++) (a:as) bs = a:((++) as bs)
(++) [] bs = bs

-- =>

recursiveFunc (x:xs) = (change x):((++) [] resursiveFunc xs)

-- =>

recursiveFunc (x:xs) = (change x):(resursiveFunc xs)

A Haskell compiler automatically applies such transformation.

But since it is so trivial it makes your code harder to read. One looks at it and asks 'wait ... what?'

like image 40
maxschlepzig Avatar answered Nov 05 '22 20:11

maxschlepzig


The primary advantage is that change x : blah is clearer -- (:) is precisely what you are trying to do (add one element to a list). Why call two functions when one will do?

The suggested way is also marginally more efficient -- your way creates a 1-element list and then throws it away and replaces it with a different list link. The other way just creates one list link. That said, the difference is small enough to be unimportant 99% of the time.

like image 22
Retief Avatar answered Nov 05 '22 18:11

Retief