I'm working my way through the Project Euler problems in Haskell. I have got a solution for Problem 3 below, I have tested it on small numbers and it works, however due to the brute force implementation by deriving all the primes numbers first it is exponentially slow for larger numbers.
-- Project Euler 3
module Main
where
import System.IO
import Data.List
main = do
hSetBuffering stdin LineBuffering
putStrLn "This program returns the prime factors of a given integer"
putStrLn "Please enter a number"
nums <- getPrimes
putStrLn "The prime factors are: "
print (sort nums)
getPrimes = do
userNum <- getLine
let n = read userNum :: Int
let xs = [2..n]
return $ getFactors n (primeGen xs)
--primeGen :: (Integral a) => [a] -> [a]
primeGen [] = []
primeGen (x:xs) =
if x >= 2
then x:primeGen (filter (\n->n`mod` x/=0) xs)
else 1:[2]
--getFactors
getFactors :: (Integral a) => a -> [a] -> [a]
getFactors n xs = [ x | x <- xs, n `mod` x == 0]
I have looked at the solution here and can see how it is optimised by the first guard in factor. What I dont understand is this:
primes = 2 : filter ((==1) . length . primeFactors) [3,5..]
Specifically the first argument of filter.
((==1) . length . primeFactors)
As primeFactors is itself a function I don't understand how it is used in this context. Could somebody explain what is happening here please?
If you were to open ghci on the command line and type
Prelude> :t filter
You would get an output of
filter :: (a -> Bool) -> [a] -> [a]
What this means is that filter takes 2 arguments.
(a -> Bool) is a function that takes a single input, and returns a Bool.
[a] is a list of any type, as longs as it is the same type from the first argument.
filter will loop over every element in the list of its second argument, and apply it to the function that is its first argument. If the first argument returns True, it is added to the resulting list.
Again, in ghci, if you were to type
Prelude> :t (((==1) . length . primeFactors))
You should get
(((==1) . length . primeFactors)) :: a -> Bool
(==1) is a partially applied function.
Prelude> :t (==)
(==) :: Eq a => a -> a -> Bool
Prelude> :t (==1)
(==1) :: (Eq a, Num a) => a -> Bool
It only needs to take a single argument instead of two.
Meaning that together, it will take a single argument, and return a Boolean.
The way it works is as follows.
primeFactors will take a single argument, and calculate the results, which is a [Int].
length will take this list, and calculate the length of the list, and return an Int
(==1) will
look to see if the values returned by length is equal to 1.
If the length of the list is 1, that means it is a prime number.
(.) :: (b -> c) -> (a -> b) -> a -> c is the composition function, so
f . g = \x -> f (g x)
We can chain more than two functions together with this operator
f . g . h === \x -> f (g (h x))
This is what is happening in the expression ((==1) . length . primeFactors).
The expression
filter ((==1) . length . primeFactors) [3,5..]
is filtering the list [3, 5..] using the function (==1) . length . primeFactors. This notation is usually called point free, not because it doesn't have . points, but because it doesn't have any explicit arguments (called "points" in some mathematical contexts).
The . is actually a function, and in particular it performs function composition. If you have two functions f and g, then f . g = \x -> f (g x), that's all there is to it! The precedence of this operator lets you chain together many functions quite smoothly, so if you have f . g . h, this is the same as \x -> f (g (h x)). When you have many functions to chain together, the composition operator is very useful.
So in this case, you have the functions (==1), length, and primeFactors being compose together. (==1) is a function through what is called operator sections, meaning that you provide an argument to one side of an operator, and it results in a function that takes one argument and applies it to the other side. Other examples and their equivalent lambda forms are
(+1) => \x -> x + 1
(==1) => \x -> x == 1
(++"world") => \x -> x ++ "world"
("hello"++) => \x -> "hello" ++ x
If you wanted, you could re-write this expression using a lambda:
(==1) . length . primeFactors => (\x0 -> x0 == 1) . length . primeFactors
=> (\x1 -> (\x0 -> x0 == 1) (length (primeFactors x1)))
Or a bit cleaner using the $ operator:
(\x1 -> (\x0 -> x0 == 1) $ length $ primeFactors x1)
But this is still a lot more "wordy" than simply
(==1) . length . primeFactors
One thing to keep in mind is the type signature for .:
(.) :: (b -> c) -> (a -> b) -> a -> c
But I think it looks better with some extra parentheses:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
This makes it more clear that this function takes two other functions and returns a third one. Pay close attention the the order of the type variables in this function. The first argument to . is a function (b -> c), and the second is a function (a -> b). You can think of it as going right to left, rather than the left to right behavior that we're used to in most OOP languages (something like myObj.someProperty.getSomeList().length()). We can get this functionality by defining a new operator that has the reverse order of arguments. If we use the F# convention, our operator is called |>:
(|>) :: (a -> b) -> (b -> c) -> (a -> c)
(|>) = flip (.)
Then we could have written this as
filter (primeFactors |> length |> (==1)) [3, 5..]
And you can think of |> as an arrow "feeding" the result of one function into the next.
This simply means, keep only the odd numbers that have only one prime factor.
In other pseodo-code: filter(x -> length(primeFactors(x)) == 1) for any x in [3,5,..]
Related
I need to check if a list only contains odd numbers, bigger than 10.
This is what I did.
f :: [Int] -> Bool
f xs= [x |x<-xs, x >10, odd x]
Why does this not work?
When you write [x |x<-xs, x >10, odd x] you're making up a list of Ints, a [Int], not a Boolean. For instance you can verify that
[x | x <- [1..20], x > 10, odd x] is the list [11,13,15,17,19]. So it does contain the numbers that you want, but how do you tell that those are all of the numebrers in xs?
You could certainly equate that list to xs itself, and that would work:
f xs = xs == [x |x<-xs, x >10, odd x]
This way the == ensures that when you only take odd numbers greater than 10 from xs you get back exactly xs, meaning that all numbers satisfy the predicate.
Maybe this is the mistake you were looking for.
I'm not sure whether this solution traverses xs twice (once to extract the entries satisfying the predicate, and once to check for equality) or not. It looks very simple, so I can't help but think that the list is traversed only once.
Anyway, another strategy is to stick to your request: you want all numbers x from the list xs for which odd x and x > 10 are both True:
f :: [Int] -> Bool
f xs = all (\x -> odd x && x > 10) xs
By noticing that both sides have a trailing xs, you can reduce the definition:
f :: [Int] -> Bool
f = all (\x -> odd x && x > 10)
And that lambda, if you want, could be define more succintly as (odd & (> 10)), thus getting
f :: [Int] -> Bool
f = all (odd & (> 10))
provided you import Control.Monad (liftM2) and define
(&) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
(&) = liftM2 (&&)
Your type signature mentions that the function returns a boolean value, but your proposed body returns a list of numbers. Haskell has no automatic conversions such as Lisp.
Should you wish to stick to pedestrian code, you could get the sublist of offending numbers, and just check that the sublist is empty.
f :: [Int] -> Bool
f xs = let offenders = [x | x <- xs, x <= 10 || even x]
in (null offenders)
Note that due to the laziness of the language runtime, evaluation of offenders stops as soon as we find a first element.
Should you want something a bit more haskell-ish, you can use the sequence :: (Traversable t, Monad m) => t (m a) -> m (t a) polymorphic library function to turn a list of predicates into a single function returning a list of boolean values, then pass that list to and. That checks one number.
Then use all to apply these checks to all numbers in the input list. Like this:
f2 :: [Int] -> Bool
f2 = all (and . sequence [(>10), odd])
Explanation:
To understand how exactly the sequence function gets specialized by the compiler, one can use the TypeApplications language extension.
With the extension enabled, given 3 type arguments, expression sequence #tt #tm #ta maps tt to the Traversable instance, tm to the Monad instance and ta to argument type a.
$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/ :? for help
λ>
λ> :type sequence
sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
λ>
λ> :set -XTypeApplications
λ>
We start with the easiest part, mapping tt to lists and ta to Bool, leaving tm undefined as an underscore _:
λ>
λ> :type sequence #[] #_ #Bool
sequence #[] #_ #Bool :: Monad _ => [_ Bool] -> _ [Bool]
λ>
Now, if we assign tm to “function of an Int variable”, we have the whole picture:
λ>
λ> :type sequence #[] #((->)Int) #Bool
sequence #[] #((->)Int) #Bool :: [Int -> Bool] -> Int -> [Bool]
λ>
The last type can be interpreted as [Int -> Bool] -> (Int -> [Bool]), that is, function sequence transforming a list of predicates into a single function returning a list of boolean values.
I understand that it's impossible to pattern match functions in Haskell, and I fully understand why. However, I have two closely related questions. First, in cases where you'd like to partially apply functions for use later, is there a way of defining and capturing the return if it's a tuple? Or am I wrong, and this is still trying to pattern match functions under my nose?
For example, suppose I'm trying to get the quotient and remainder of a value with various multiples of ten. Then, how would I write something like this?
q, r :: Integral a => a -> a
(q, r) = (12345 `quotRem`)
I realize here, there are separate functions that exist, so I could do this instead:
q, r :: Integral a => a -> a
q = (12345 `quot`)
r = (12345 `rem`)
However, that's a very specific case, and there are unlimited other examples of functions that return tuples that would be nice to generalize. For example, a function that returns the number of evens and odds in a list.
evens, odds :: Integral a => [a] -> Int
(evens, odds) = (length . (filter even), length . (filter odd))
This leads me to my second question. The above works just fine in GHCi.
Prelude> let (evens, odds) = (length . (filter even), length . (filter odd))
Prelude> :t evens
evens :: Integral a => [a] -> Int
Prelude> evens [1..10]
5
What's even more confusing is it even works by "pattern-matching" in the same way that I was playing with (q, r) in the beginning:
Prelude> let evensOdds = (length . (filter even), length . (filter odd))
Prelude> :t evensOdds
evensOdds :: (Integral a1, Integral a) => ([a1] -> Int, [a] -> Int)
Prelude> let (ev,od) = evensOdds
Prelude> :t ev
ev :: Integral a1 => [a1] -> Int
Prelude> ev [1..10]
5
It also works just fine in an actual file loaded into GHCi, even though (evens, odds) doesn't. Why are these two different, and why does the second one work in GHCi at all if it doesn't work normally? Can what's different here be leveraged in some way?
You never pattern matched on a function. You always pattern matched on the pair-constructor (,). Your (even, odds) example
(evens, odds) = (length . (filter even), length . (filter odd))
just works like
(first, second) = (x, y)
It doesn't matter what type x and y have at that point.
Your (q, r) example doesn't work due to quotRem's type. Let's recall it and compare it with (q, r)'s type:
quotRem :: Integral n => n -> n -> (n , n)
quotRem 12345 :: Integral n => n -> (n , n)
(q, r) :: Integral n => (n -> n, n -> n)
As you can see, the pair (q, r)'type differs from quotRem's one. Still, it's possible to write your function:
pairify :: (a -> (b, c)) -> (a -> b, a -> c)
pairify f = (fst . f, snd . f)
(q,r) = pairify (quotRem 12345)
But as you can see we don't gain too much from pairify. By the way, partition from Data.List provides your (even, odds) functionality:
(even, odds) = pairify (partition even)
Look at the type of (12345 `quotRem`):
Integral a => a -> (a, a)
It’s a single function that returns a tuple. If you want to make this into a tuple of functions, you can compose it with fst and snd:
(q, r) = (fst . f, snd . f)
where f = (12345 `quotRem`)
If you want to do this in a point-free way, one way is to use the &&& combinator from Control.Arrow. Its fully general type is:
Arrow a => a b c -> a b d -> a b (c, d)
Specialised to the -> arrow, that’s:
(b -> c) -> (b -> d) -> b -> (c, d)
So it takes two functions, each taking a value of type b, and returns both their results (of types c and d) in a tuple. So here you can do something like this:
split = (fst .) &&& (snd .)
(q, r) = split (12345 `quotRem`)
Whereas if you look at the type of (length . filter even, length . filter odd), it’s a tuple already,
(Integral a, Integral b) => ([a] -> Int, [b] -> Int)
Which is why of course you can destructure this tuple to bind evens and odds.
> type Client = (Text, WS.Connection)
The state kept on the server is simply a list of connected clients. We've added
an alias and some utility functions, so it will be easier to extend this state
later on.
> type ServerState = [Client]
Check if a user already exists (based on username):
> clientExists :: Client -> ServerState -> Bool
> clientExists client = any ((== fst client) . fst)
Remove a client:
> removeClient :: Client -> ServerState -> ServerState
> removeClient client = filter ((/= fst client) . fst)
This is a literal haskell code taken from websockets. I don't understand how does clientExists function works,
clientExists client = any ((== fst client) . fst)
This function is invoked as,
clientExists client clients
So, how does the function refer the second argument clients? and what does . operator do?
And again at removeClient, what does the operator `/=' stand for?
The . operator is the function composition operator, it's defined as
f . g = \x -> f (g x)
The /= operator is "not equals", usually written as != in other languages.
The clientExists function has two arguments, but the second one is left off since it's redundant. It could have been written as
clientExists client clients = all ((== fst client) . fst) clients
But Haskell allows you to drop the last argument in situations like this. The any function has the type (a -> Bool) -> [a] -> Bool, and the function any ((== fst client) . fst) has the type [a] -> Bool. This is saying that the function clientExists client is the same function as any ((== fst client) . fst).
Another way to think of it is that Haskell does not have multi-argument functions, only single argument functions that return new functions. This is because -> is right associative, so a type signature like
a -> b -> c -> d
Can be written as
a -> (b -> (c -> d))
without changing its meaning. With the second type signature it's more clear that you have a function that when given an a, returns a function of type b -> (c -> d). If it's next given a b, it returns a function of type c -> d. Finally, if this is given a c it just returns a d. Since function application in Haskell is so cheap (just a space), this is transparent, but it comes in handy. For example, it means that you can write code like
incrementAll = map (+1)
or
onlyPassingStudents = filter ((>= 70) . grade)
In both of these cases I've also used operator sections, where you can supply either argument to an operator, and so long as its wrapped in parens it works. Internally it looks more like
(x +) = \y -> x + y
(+ x) = \y -> y + x
Where you can swap out the + for any operator you please. If you were to expand the definition of clientExists to have all argument specified it would look more like
clientExists client clients = any (\c -> fst c == fst client) clients
This definition is exactly equivalent to the one you have, just de-sugared to what the compiler really uses internally.
When in doubt, use the GHCi interpreter to find out the types of the functions.
First off, the /= operator is the not-equal:
ghci> :t (/=)
(/=) :: Eq a => a -> a -> Bool
ghci> 5 /= 5
False
ghci> 10 /= 5
True
. is the composition of two functions. It glues two functions together, just like in mathematics:
ghci> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
ghci> :t head.tail
head.tail :: [c] -> c
ghci> (head.tail) [1, 2, 3]
2
With the basics covered, let's see how it is used in your function definition:
ghci> :t (\x -> (== fst x))
(\x-> (== fst x)) :: Eq a => (a, b) -> a -> Bool
ghci> :t (\x-> (== fst x) . fst)
(\x-> (== fst x) . fst) :: Eq b => (b, b1) -> (b, b2) -> Bool
ghci> (\x -> (== fst x) . fst) (1, "a") (1, "b")
True
ghci> (\x -> (== fst x) . fst) (1, "a") (2, "b")
False
As we can see, the (== fst x) . fst is used to take two tuples, and compare the first element each for equality. Now, this expression (let's call it fstComp) has type fstComp :: Eq b => (b, b1) -> (b, b2) -> Bool, but we are already passing it a defined tuple (client :: (Text, WS.Connection)), we curry it to (Text, b2) -> Bool.
Since we have any :: (a -> Bool) -> [a] -> Bool, we can unify the first parameter with the previous type to have an expression of type (Text, b2) -> [(Text, b2)] -> Bool. Instantiating b2 = WS.Connection we get the type of clientExists :: (Text, WS.Connection) -> [(Text, WS.Connection)] -> Bool, or using the type synonyms, clientExists :: Client -> ServerState -> Bool.
Brief: This is a past exam question from a Miranda exam but the syntax is very similar to Haskell.
Question: What is the type of the following expression and what does it do? (The definitions
of the functions length and swap are given below).
(foldr (+) 0) . (foldr ((:) . length . (swap (:) [] )) [])
length [] = 0
length (x:xs) = 1 + length xs
swap f x y = f y x
Note:
Please feel free to reply in haskell syntax - sorry about putting using the stars as polytypes but i didn't want to translate it incorrectly into haskell. Basically, if one variable has type * and the other has * it means they can be any type but they must both be the same type. If one has ** then it means that it can but does not need to have the same type as *. I think it corresponds to a,b,c etc in haskell usuage.
My working so far
From the definition of length you can see that it finds the length of a list of anything so this gives
length :: [*] -> num.
From the definition I think swap takes in a function and two parameters and produces the function with the two parameters swapped over, so this gives
swap :: (* -> ** -> ***) -> ** -> [*] -> ***
foldr takes a binary function (like plus) a starting value and list and folds the list from right to left using that function. This gives
foldr :: (* -> ** -> **) -> ** -> [*] -> **)
I know in function composition it is right associative so for example everything to the right of the first dot (.) needs to produce a list because it will be given as an argument to the first foldr.
The foldr function outputs a single value ( the result of folding up the list) so I know that the return type is going to be some sort of polytype and not a list of polytype.
My problem
I'm unsure where to go from here really. I can see that swap needs to take in another argument, so does this partial application imply that the whole thing is a function? I'm quite confused!
You've already got the answer, I'll just write down the derivation step by step so it's easy to see all at once:
xxf xs = foldr (+) 0 . foldr ((:) . length . flip (:) []) [] $ xs
= sum $ foldr ((:) . length . (: [])) [] xs
= sum $ foldr (\x -> (:) (length [x])) [] xs
= sum $ foldr (\x r -> length [x]:r) [] xs
= sum $ map (\x -> length [x] ) xs
= sum [length [x] | x <- xs]
= sum [ 1 | x <- xs]
-- = length xs
xxf :: (Num n) => [a] -> n
So that, in Miranda, xxf xs = #xs. I guess its type is :: [*] -> num in Miranda syntax.
Haskell's length is :: [a] -> Int, but as defined here, it is :: (Num n) => [a] -> n because it uses Num's (+) and two literals, 0 and 1.
If you're having trouble visualizing foldr, it is simply
foldr (+) 0 (a:(b:(c:(d:(e:(...:(z:[])...))))))
= a+(b+(c+(d+(e+(...+(z+ 0)...)))))
= sum [a, b, c, d, e, ..., z]
Let's go through this step-by-step.
The length function obviously has the type that you described; in Haskell it's Num n => [a] -> n. The equivalent Haskell function is length (It uses Int instead of any Num n).
The swap function takes a function to invoke and reverses its first two arguments. You didn't get the signature quite right; it's (a -> b -> c) -> b -> a -> c. The equivalent Haskell function is flip.
The foldr function has the type that you described; namely (a -> b -> b) -> b -> [a] -> b. The equivalent Haskell function is foldr.
Now, let's see what each sub expression in the main expression means.
The expression swap (:) [] takes the (:) function and swaps its arguments. The (:) function has type a -> [a] -> [a], so swapping it yields [a] -> a -> [a]; the whole expression thus has type a -> [a] because the swapped function is applied to []. What the resulting function does is that it constructs a list of one item given that item.
For simplicity, let's extract that part into a function:
singleton :: a -> [a]
singleton = swap (:) []
Now, the next expression is (:) . length . singleton. The (:) function still has type a -> [a] -> [a]; what the (.) function does is that it composes functions, so if you have a function foo :: a -> ... and a function bar :: b -> a, foo . bar will have type b -> .... The expression (:) . length thus has type Num n => [a] -> [n] -> [n] (Remember that length returns a Num), and the expression (:) . length . singleton has type Num => a -> [n] -> [n]. What the resulting expression does is kind of strange: given any value of type a and some list, it will ignore the a and prepend the number 1 to that list.
For simplicity, let's make a function out of that:
constPrependOne :: Num n => a -> [n] -> [n]
constPrependOne = (:) . length . singleton
You should already be familiar with foldr. It performs a right-fold over a list using a function. In this situation, it calls constPrependOne on each element, so the expression foldr constPrependOne [] just constructs a list of ones with equal length to the input list. So let's make a function out of that:
listOfOnesWithSameLength :: Num n => [a] -> [n]
listOfOnesWithSameLength = foldr constPrependOne []
If you have a list [2, 4, 7, 2, 5], you'll get [1, 1, 1, 1, 1] when applying listOfOnesWithSameLength.
Then, the foldr (+) 0 function is another right-fold. It is equivalent to the sum function in Haskell; it sums the elements of a list.
So, let's make a function:
sum :: Num n => [n] -> n
sum = foldr (+) 0
If you now compose the functions:
func = sum . listOfOnesWithSameLength
... you get the resulting expression. Given some list, it creates a list of equal length consisting of only ones, and then sums the elements of that list. It does in other words behave exactly like length, only using a much slower algorithm. So, the final function is:
inefficientLength :: Num n => [a] -> n
inefficientLength = sum . listOfOnesWithSameLength
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
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
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.
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.
The . operator is used for function composition. Just like math, if you have to functions f(x) and g(x) f . g becomes f(g(x)).
map is a built-in function which applies a function to a list. By putting the function in parentheses the function is treated as an argument. A term for this is currying. You should look that up.
What is does is that it takes a function with say two arguments, it applies the argument euler. (map euler) right? and the result is a new function, which takes only one argument.
sum . (map euler) . mkList is basically a fancy way of putting all that together. I must say, my Haskell is a bit rusty but maybe you can put that last function together yourself?
Dot Operator in Haskell
I'm trying to understand what the dot operator is doing in this Haskell code:
sumEuler = sum . (map euler) . mkList
Short answer
Equivalent code without dots, that is just
sumEuler = \x -> sum ((map euler) (mkList x))
or without the lambda
sumEuler x = sum ((map euler) (mkList x))
because the dot (.) indicates function composition.
Longer answer
First, let's simplify the partial application of euler to map:
map_euler = map euler
sumEuler = sum . map_euler . mkList
Now we just have the dots. What is indicated by these dots?
From the source:
(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)
Thus (.) is the compose operator.
Compose
In math, we might write the composition of functions, f(x) and g(x), that is, f(g(x)), as
(f ∘ g)(x)
which can be read "f composed with g".
So in Haskell, f ∘ g, or f composed with g, can be written:
f . g
Composition is associative, which means that f(g(h(x))), written with the composition operator, can leave out the parentheses without any ambiguity.
That is, since (f ∘ g) ∘ h is equivalent to f ∘ (g ∘ h), we can simply write f ∘ g ∘ h.
Circling back
Circling back to our earlier simplification, this:
sumEuler = sum . map_euler . mkList
just means that sumEuler is an unapplied composition of those functions:
sumEuler = \x -> sum (map_euler (mkList x))
The dot operator applies the function on the left (sum) to the output of the function on the right. In your case, you're chaining several functions together - you're passing the result of mkList to (map euler), and then passing the result of that to sum.
This site has a good introduction to several of the concepts.