performance – Very slow algorithm in Haskell (Advent of Code 2018)

I've been trying to do the second part of the December 1 Advent of Code Challenge in Haskell. I am fairly new at Haskell but I have a lot of experience in other languages ​​(procedural). I struggled to meet the challenge for hours because the program was crashing and it was producing no output although I could not find a problem in my code. Eventually, it turned out that my program was working properly, but it took a very long time. To be exact, the program took 2 minutes and 40 seconds. According to Advent of Code, each challenge should be able to run within 15 seconds.

So what makes my code so slow?


You notice that the device is constantly repeating the same list of frequency changes. To calibrate the device, you must find the first frequency that it reaches twice.

For example, using the same list of changes above, the device
loop as follows:

Current frequency 0, +1 change; resulting frequency 1.
Current frequency 1, change -2; resulting frequency -1.
Current frequency -1, change of +3; resulting frequency 2.
Current frequency 2, +1 change; resulting frequency 3.
(At this point, the device continues from the beginning of the list.)
Current frequency 3, +1 change; resulting frequency 4.
Current frequency 4, change -2; the resulting frequency 2, which has already been seen.

In this example, the first frequency reached twice is 2. Note that
your device may need to repeat its list of many frequency changes
time before a doubling frequency is found, and that duplicates could
to be found while processing the list.

Here are some other examples:

+1, -1 the first reaches 0 twice.
+3, +3, +4, -2, -4 reaches 10 twice.
-6, +3, +8, +5, -6 reaches 5 twice.
+7, +7, -2, -7, -4 reaches 14 twice.

What is the first frequency at which your device reaches twice?

My code:

DayOnePartTwo module where

import System.IO
Import Data.Maybe

inputFileName = "input.txt"

input :: String -> [Integer]
    input content = toNum (cleanNumbers (content of splitNumbers))
cleanNumbers strs = map removeLeadingPlus strs
splitNumbers string = string words
toNum numbers = map numbers read
removeLeadingPlus str = if str !! 0 == & # 39; + & # 39; then tail str otherwise str

accumulate :: [Integer] -> [Integer]
    accumulate list = list of accumulators 0
accumulator :: Num a => [a] -> a -> [a]
            accumulator (x: xs) state = (x + state): accumulator xs (x + state)
accumulator [] state = []

    duplicate :: [Integer] -> Maybe Integer
duplicate list = dup list [0]
dup (x: xs) visited =
if elem x has visited
so just x
otherwise dup xs (x: visited)
dup [] _ = Nothing

firstCyclicDuplicate :: [Integer] -> Maybe Integer
firstCyclicDuplicate list = duplicate (accumulate cycledList)
cycledList = cycle list

main :: IO ()
main = do
contents <- readFile inputFileName
        case (firstCyclicDuplicate (input contents)) of
            Just a -> print (show a)
Nothing -> print "There is no first duplicate"


This seems to be related to the slow advent of the 2018 code solution, day 1, part 2 in haskell, although my algorithm is different.