2
votes

again another question generated by my attempts at the Project Euler questions (follow on from a previous question). I'm having trouble understanding the following line:

print (maximum (map (product . take 13) (tails number)))

Specifically

map (product . take 13) (tails number)

The type signature for the first argument of map from ghci is [c] -> c:

ghci> :t (product . take 13)
(product . take 13) :: Num c => [c] -> c

The type signature for map (product . take 13) from ghci is [[b]] -> [b]:

ghci> :t map (product . take 13)
map (product . take 13) :: Num b => [[b]] -> [b]

Am I right in saying that as the first argument of map should be a function, [[b]] is not referring to a list of lists, but rather to a list of (partially applied) functions generated by (product . take 13), with the second argument for the partial functions coming from (tails number)?

2
no - product . take 13 is already a function (here from a list of some c (where c is an instance of Num because we want to multiply cs) to c) you should read it from right-to-left: first you take all final-segments list of numbers (see tails), then you multiply the numbers (but only the first 13) in there for each of these segments (map (product . take 13)), then you take the maximum of these products (remember one for each segment) and finally you print itRandom Dev
when some code is hard to understand, simplify! Prelude Data.List> map (take 4) (tails [1..5]) ==> [[1,2,3,4],[2,3,4,5],[3,4,5],[4,5],[5],[]]. This is faulty (only 2 subsequences, of length 4, should be considered here); check out my recent answer to your previous question.Will Ness

2 Answers

3
votes

Here is a point-free version:

euler8 :: (Ord c, Num c) => [c] -> c
euler8 = maximum . map (product . take 13) . tails

let's make this a bit more obvious:

euler8' numbers = 
  let segments = tails numbers
      groups   = map (take 13) segments -- only take up to 13 numbers from each segment
      products = map product groups
      max      = maximum products
  in max

so as you can see - it first gets the final-segments of the numbers-list (this is a list again)

then it uses map to get the product for each of these segments (again a list)

and finaly it searches for the maximum of those products and returns it

PS: I striped the print in both versions - I think the IO will just complicate matters and it's not really important ... you can always print it out afterwards ;)

1
votes

Am I right in saying that as the first argument of map should be a function ?

Yes, the first argument of map should be a function. See it's type:

λ> :t map
map :: (a -> b) -> [a] -> [b]

It takes a function of type (a -> b). But in your case the a -> b refers to (product . take 13):

λ> :t (product . take 13)
(product . take 13) :: Num a => [a] -> a

So, this is a function which takes a list of elements [a] and produces a single value of type a from it. You can actually test this in ghci:

λ> (product . take 14) [1,2,3]
6

For simplicity, it gets applied like this:

(\x -> product (take 14 x)) [1,2,3]

the second argument for the partial functions coming from (tails number)?

tails is a normal function with the type:

λ> :t tails
tails :: [a] -> [[a]]

So, this function accepts a list of element and gives you a list of list of elements. You can play with this around in ghci:

λ> tails [1,2]
[[1,2],[2],[]]

I hope that makes it clear.