Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dot Operator in Haskell: need more explanation

I'm trying to understand what the dot operator is doing in this Haskell code:

sumEuler = sum . (map euler) . mkList

The entire source code is below.

My understanding

The dot operator is taking the two functions sum and the result of map euler and the result of mkList as the input.

But, sum isn't a function it is the argument of the function, right? So what is going on here?

Also, what is (map euler) doing?

Code

mkList :: Int -> [Int]
mkList n = [1..n-1]

euler :: Int -> Int
euler n = length (filter (relprime n) (mkList n))

sumEuler :: Int -> Int
sumEuler = sum . (map euler) . mkList
like image 512
cbrulak Avatar asked Mar 10 '09 16:03

cbrulak


People also ask

What does the dot operator do in Haskell?

Dot operator in Haskell is completely similar to mathematics composition: f{g(x)} where g() is a function and its output used as an input of another function, that is, f(). The result of . (dot) operator is another function (or lambada) that you can use and call it.

What does the period mean in Haskell?

In general terms, where f and g are functions, (f . g) x means the same as f (g x). In other words, the period is used to take the result from the function on the right, feed it as a parameter to the function on the left, and return a new function that represents this computation."

What does >> mean in Haskell?

Essentially, a >> b can be read like "do a then do b , and return the result of b ". It's similar to the more common bind operator >>= .

Is there and operator in Haskell?

In Haskell we have or operator to compare the values of the variable, this operator also comes under the lexical notation of the Haskell programming language. This operator works in the same way as any other programming language, it just returns true or false based on the input we have provided.


3 Answers

Put simply, . is function composition, just like in math:

f (g x) = (f . g) x

In your case, you are creating a new function, sumEuler that could also be defined like this:

sumEuler x = sum (map euler (mkList x))

The style in your example is called "point-free" style -- the arguments to the function are omitted. This makes for clearer code in many cases. (It can be hard to grok the first time you see it, but you will get used to it after a while. It is a common Haskell idiom.)

If you are still confused, it may help to relate . to something like a UNIX pipe. If f's output becomes g's input, whose output becomes h's input, you'd write that on the command-line like f < x | g | h. In Haskell, . works like the UNIX |, but "backwards" -- h . g . f $ x. I find this notation to be quite helpful when, say, processing a list. Instead of some unwieldy construction like map (\x -> x * 2 + 10) [1..10], you could just write (+10) . (*2) <$> [1..10]. (And, if you want to only apply that function to a single value; it's (+10) . (*2) $ 10. Consistent!)

The Haskell wiki has a good article with some more detail: http://www.haskell.org/haskellwiki/Pointfree

like image 72
jrockway Avatar answered Oct 13 '22 17:10

jrockway


The . operator composes functions. For example,

a . b

Where a and b are functions is a new function that runs b on its arguments, then a on those results. Your code

sumEuler = sum . (map euler) . mkList

is exactly the same as:

sumEuler myArgument = sum (map euler (mkList myArgument))

but hopefully easier to read. The reason there are parens around map euler is because it makes it clearer that there are 3 functions being composed: sum, map euler and mkList - map euler is a single function.

like image 32
Jesse Rusak Avatar answered Oct 13 '22 16:10

Jesse Rusak


sum is a function in the Haskell Prelude, not an argument to sumEuler. It has the type

Num a => [a] -> a

The function composition operator . has type

(b -> c) -> (a -> b) -> a -> c

So we have

           euler           ::  Int -> Int
       map                 :: (a   -> b  ) -> [a  ] -> [b  ]
      (map euler)          ::                 [Int] -> [Int]
                    mkList ::          Int -> [Int]
      (map euler) . mkList ::          Int ->          [Int]
sum                        :: Num a =>                 [a  ] -> a
sum . (map euler) . mkList ::          Int ->                   Int

Note that Int is indeed an instance of the Num typeclass.

like image 27
Chris Conway Avatar answered Oct 13 '22 16:10

Chris Conway