Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding function composition with negate

After reading through a page on Higher Order Functions from an awesome site I am still having trouble understanding the negate function paired with function composition.

to be more specific, take this piece of code:

ghci> map (negate . sum . tail) [[1..5],[3..6],[1..7]]

which yields:

[-14,-15,-27] 

I re-read the page again, but to be honest, I still have no idea how that line of code produced this answer, if someone could walk me through the process of this I would really appreciate it!

like image 965
Syntactic Fructose Avatar asked Nov 30 '22 03:11

Syntactic Fructose


2 Answers

map f [a,b,c] = [f a,  f b,  f c]

because map f (x:xs) = f x:map f xs - apply f to each element of the list.

So

map (negate.sum.tail) [[1..5],[3..6],[1..7]]
= [(negate.sum.tail) [1..5],   (negate.sum.tail) [3..6],   (negate.sum.tail) [1..7]]

now

(negate . sum . tail) [1..5]
= negate (sum (tail [1,2,3,4,5]))
= negate (sum  [2,3,4,5])
= negate 14
= -14

because (f.g) x = f (g x) and . is right associative, so (negate.sum.tail) xs = (negate.(sum.tail)) xs which in turn is negate ((sum.tail) xs) = negate (sum (tail xs)).

tail gives you everything except the first element of a list: tail (x:xs) = xs, for example tail "Hello" = "ello" sum adds them up as you expect, and
negate x = -x.

The others work similarly, giving minus the sum of the tail of each list.

like image 148
AndrewC Avatar answered Dec 05 '22 05:12

AndrewC


To add a different perspective to AndrewC's excellent answer I usually think about these types of problems in terms of the functor laws and fmap. Since map can be thought of as a specialization of fmap to lists we can replace map with the more general fmap and keep the same functionality:

ghci> fmap (negate . sum . tail) [[1..5],[3..6],[1..7]]

Now we can apply the composition functor law using algebraic substitution to shift where the composition is happening and then map each function individually over the list:

fmap (f . g)  ==  fmap f . fmap g -- Composition functor law

fmap (negate . sum . tail)             $ [[1..5],[3..6],[1..7]]
== fmap negate . fmap (sum . tail)     $ [[1..5],[3..6],[1..7]]
== fmap negate . fmap sum . fmap tail  $ [[1..5],[3..6],[1..7]]
== fmap negate . fmap sum $    fmap tail [[1..5],[3..6],[1..7]]
== fmap negate . fmap sum              $ [tail [1..5],tail [3..6],tail [1..7]] -- As per AndrewC's explanation
== fmap negate . fmap sum              $ [[2..5],[4..6],[2..7]]
== fmap negate                         $ [14, 15, 27]
==                                       [-14, -15, -27]
like image 29
Davorak Avatar answered Dec 05 '22 04:12

Davorak