我是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
以上代码是我省略的递归的一部分。 addRecipes
在递归调用中被反复调用。这是解决代码问题(AoC 2018第14天)的解决方案。该代码可产生正确的结果,但速度非常慢。
我只是想了解问题出在哪里,在上面的代码中什么效率低下?
我尝试优化++
运算符,并用:
代替它,并将其与数字调用结合起来。我知道++
比:
慢,但这是真的吗? (请记住,我正在学习Haskell,所以我想尽可能修复此代码,并知道为什么我不能这样写)
编辑:“食谱”中的列表会增加并变大
答案 0 :(得分:1)
我遵循了评论中发布的建议;进行大量随机访问时,请勿使用列表数据结构。所以我用序列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)
它可以正常工作,并且运行时间现在合理(从1小时到几秒钟)。谢谢评论者!