Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
haskell产生堆栈溢出的可能尾部递归解决方案_Haskell_Recursion - Fatal编程技术网

haskell产生堆栈溢出的可能尾部递归解决方案

haskell产生堆栈溢出的可能尾部递归解决方案,haskell,recursion,Haskell,Recursion,我一直在试图解决adventofcode第5天的问题2()。它不同于第一个问题,如果项目大于等于3,则减少而不是增加1 当使用测试数据运行实现时,它会产生正确的结果,因此实现似乎是完美的。此外,递归调用看起来处于尾部位置,但它仍然产生stackoverflow异常 代码如下所示 module AdventOfCode5 where type Instruction = Int type Position = Int main :: IO () main = do input <-

我一直在试图解决adventofcode第5天的问题2()。它不同于第一个问题,如果项目大于等于3,则减少而不是增加1

当使用测试数据运行实现时,它会产生正确的结果,因此实现似乎是完美的。此外,递归调用看起来处于尾部位置,但它仍然产生stackoverflow异常

代码如下所示

module AdventOfCode5 where

type Instruction = Int
type Position = Int

main :: IO ()
main = do
  input <- readFile "day5input.txt"
  let instructions = fmap (read :: String -> Instruction) $ lines input
  _ <- putStrLn $ show $ computeResult (Prelude.length instructions) 0 (+1) $ instructions
  return ()

main2 :: IO ()
main2 = do
  input <- readFile "day5input.txt"
  let instructions = fmap (read :: String -> Instruction) $ lines input
  _ <- putStrLn $ show $ computeResult (Prelude.length instructions) 0 decAbove3AndIncBelow3 instructions
  return ()

decAbove3AndIncBelow3 :: Int -> Int
decAbove3AndIncBelow3 x
  | x >= 3 = x - 1
  | otherwise = x + 1

computeResult :: Int -> Position -> (Int -> Int) -> [Instruction] -> Int
computeResult = takeStep' 0
  where takeStep' :: Int -> Int -> Position -> (Int -> Int) -> [Instruction] -> Int
        takeStep' count max pos changeInteger instructions
          | pos >= max = count
          | otherwise =
              let
                elementAtPos = instructions!!pos
                newCount = count + 1
                newPos = pos + elementAtPos
                newInstructions = (take pos instructions) ++ ([(changeInteger elementAtPos)]) ++ (drop (pos + 1)) instructions
              in
                takeStep' newCount max newPos changeInteger newInstructions
模块代码5,其中
类型指令=Int
类型位置=Int
main::IO()
main=do
输入指令)$行输入
_=3=x-1
|否则=x+1
计算机结果::Int->Position->(Int->Int)->[指令]->Int
计算机结果=执行步骤“0”
其中takeStep'::Int->Int->Position->(Int->Int)->[指令]->Int
takeStep“count max pos changeInteger指令
|位置>=最大值=计数
|否则=
让
elementAtPos=说明!!销售时点情报系统
newCount=count+1
newPos=pos+elementAtPos
新指令=(接受pos指令)+([(changeInteger elementAtPos)])++(删除(pos+1))指令
在里面
takeStep'newCount max newPos changeInteger newInstructions
该实现的思想是,您持有一个计数器,并为每次迭代递增计数器,同时使用更新的版本更改指令列表(其中Int->Int是知道如何更新的函数)。您得到了一个要查看的位置,当该位置大于列表大小(我将其作为输入传递,但也可以从指令列表派生)时,递归就会停止


有人能解释一下为什么这个会产生堆栈溢出吗?

takeStep'的第一个参数中有一个空格泄漏,因为它构建了一个thunk
(…((0+1)+1)…+1
,而不是仅仅计算整数

当计算该thunk时,堆栈可能会爆炸

  • 在继续之前,使用
    seq
    强制
    count
    ,例如,在防护装置中使用
    count`seq`否则
  • 或者通过优化进行编译
ghci
正在解释它,而不是编译它。特别是,它不执行自动修复泄漏所需的严格性分析

您可以运行此命令进行优化编译(
-O


(尽管即使没有优化,编译似乎也能减少足够的空间使用,从而取得成功。)

您是如何运行程序的?stackoverflow发生需要多长时间?FWIW,我今天早些时候也做了这个练习,第二个拼图确实花了足够长的时间运行,我去刷牙,等待它完成-它完成了,26948068步!这是我的代码,以防有人感兴趣:我无法重现堆栈溢出,但
takeStep'
的第一个参数中有一个空间泄漏,可以通过强制或优化编译来修复。@李耀霞我只在repl中运行它,首先加载它(:l adventofcode5.hs)然后只运行main2。@李耀霞如何通过优化编译?我在运行了很长一段时间后(可能15分钟)出现堆栈溢出。我的电脑在两者之间睡眠,但这不应该是一个问题,对吧,这确实似乎是问题所在,谢谢你解释如何解决这个问题!
ghc -O -main-is AdventOfCode5.main2 AdventOfCode5.hs