TL;DR:
maximum . map product . takeWhile ((==n).length) . map (take n) . tails
Compose functions
You can do this very cleanly by composing functions:
import Data.List (tails)
import Data.Char (isDigit)
maxProd :: (Num a, Ord a) => Int -> [a] -> a
maxProd n = maximum -- biggest
. map product -- product in the list
. takeWhile ((== n) . length) -- once the too-short ones have gone
. map (take n) -- when you take the first n of each
. tails -- of the tails of the original
Note that
((== n) . length) :: [a] -> Bool
first finds the length of the list, then gives True
if that length matches n
.
How does it work?
By way of illustration, let's track that through on your example. Notice how the tails have all lengths, but then when we map (take 3)
it just keeps the first three of each. Also notice there are three lists that are too short ([1,3],[3],[]
), so that's why we takeWhile ((==3).length)
.
ghci> tails $ [1,2,4,0,3,1,3]
[[1,2,4,0,3,1,3],[2,4,0,3,1,3],[4,0,3,1,3],[0,3,1,3],[3,1,3],[1,3],[3],[]]
ghci> map (take 3) . tails $ [1,2,4,0,3,1,3]
[[1,2,4],[2,4,0],[4,0,3],[0,3,1],[3,1,3],[1,3],[3],[]]
ghci> takeWhile ((==3).length) . map (take 3) . tails $ [1,2,4,0,3,1,3]
[[1,2,4],[2,4,0],[4,0,3],[0,3,1],[3,1,3]]
ghci> map product . takeWhile ((==3).length) . map (take 3) . tails $ [1,2,4,0,3,1,3]
[8,0,0,0,9]
ghci> maximum . map product . takeWhile ((==3).length) . map (take 3) . tails $ [1,2,4,0,3,1,3]
9
Making it less unhelpful
Now this gives an error when n
is more than the original list's length because the takeWhile
will filter out all of the lists, and you'll be taking the maximum of an empty list, but it'll be more helpful with a clearer message. It's also handy to convert from a single Int:
digits :: Int -> [Int]
digits = map (read . (:"")) . show
That works by turning each character of the shown String into a String itself by putting it in front of the empty String with (:""), then reading each. Originally I had it taking from a String, because I erroneously thought that's what you had. Never mind.
findMaxProd :: Int -> Int -> Int
findMaxProd n i
| n > length (show i) = error "findMaxProd: product length exceeds number length"
| otherwise = maxProd n . digits $ i
In action, that gives:
ghci> findMaxProd 10 1240313
*** Exception: findMaxProd: product length exceeds number length
ghci> findMaxProd 3 1240313
9