Reputation: 3013
I'm very much a beginner in Haskell
data Recipes = Recipes Int Int Int [Int] deriving(Show)
addRecipes :: Recipes -> Recipes
addRecipes (Recipes t e1 e2 list) =
let (e1c, e2c) = (list !! e1, list !! e2)
newVal = e1c + e2c
newList = list ++ (digits $ newVal)
e1n = calcNewPos e1 e1c newList
e2n = calcNewPos e2 e2c newList
in Recipes t e1n e2n newList
calcNewPos :: Int -> Int -> [Int] -> Int
calcNewPos i i2 list = (i + i2 + 1) `mod` (length list)
-- Borrowed:
-- https://stackoverflow.com/questions/3963269/split-a-number-into-its-digits-with-haskell
digits :: Int -> [Int]
digits = map (read . (:[])) . show
The above piece of code is part of a recursion which I omitted. The addRecipes
is called again and again in a recursive call. This is a solution to an advent of code problem (AoC 2018 day 14). The code produces the correct result but is cripplingly slow.
I'm just trying to learn where the problem lies, what is horribly inefficient in the code above?
I've tried optimizing away the ++
-operator and replace it with a :
and combining things with the digits call. I know the ++
is slower than the :
but is that really it? (Remember, i'm learning Haskell so I want to fix this code if possible and know why I can't write it like this)
Edit: The list in Recipes grows and becomes large
Upvotes: 1
Views: 193
Reputation: 3013
I followed the advice posted in the comments; Do not use a the list data structure when you make a lot of random accesses. So I replaced the list with with Sequence http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Sequence.html
import qualified Data.Sequence as Seq
data Recipes = Recipes Int Int Int (Seq.Seq Int) deriving(Show)
addRecipes :: Recipes -> Recipes
addRecipes (Recipes t e1 e2 seq) =
let (e1c, e2c) = (Seq.index seq e1, Seq.index seq e2)
newVal = e1c + e2c
newSeq = (Seq.><) seq (Seq.fromList (digits newVal))
e1n = calcNewPos e1 e1c newSeq
e2n = calcNewPos e2 e2c newSeq
in Recipes t e1n e2n newSeq
calcNewPos :: Int -> Int -> (Seq.Seq Int) -> Int
calcNewPos i i2 seq = (i + i2 + 1) `mod` (Seq.length seq)
It worked and the run time is now reasonable (from 1 hour to seconds). Thanks commenters!
Upvotes: 1