免责声明:我在reddit上问了同样的问题(link)
我正在 Elm 中重写 Haskell 应用程序(由我的学生使用)来训练自己的语言能力,并启用部署为静态 Web 应用程序以简化托管。我遇到了一个奇怪的问题:函数
runTrace
似乎抛出了堆栈溢出错误(RangeError:超出最大调用堆栈大小),这是意外的,因为该函数是尾递归的。更奇怪的是,启用该功能的日志记录完全解决了该错误。我很难理解为什么会发生这种情况或如何解决它。此外,当我尝试在 Ellie 上运行代码时,即使启用了日志记录,它也无法工作(OutputUncaught TypeError 中抛出异常:无法读取未定义的属性(读取“init”)。
带有日志记录的代码:
runTrace : ComputationModel model state input output -> model -> input -> ( List state, output )
runTrace cm instance input =
let
runTrace_ acc state =
case cm.update instance state of
Err newState ->
(log <| "newState: " ++ Debug.toString newState) <|
runTrace_ (\trace -> acc (newState :: trace)) newState
Ok output ->
( acc [], output )
in
runTrace_ identity <| cm.init instance input
且无需登录:
runTrace : ComputationModel model state input output -> model -> input -> ( List state, output )
runTrace cm instance input =
let
runTrace_ acc state =
case cm.update instance state of
Err newState ->
runTrace_ (\trace -> acc (newState :: trace)) newState
Ok output ->
( acc [], output )
in
runTrace_ identity <| cm.init instance input
问题不在于
runTrace_
本身不是尾递归,而是您创建的累加器函数没有从 TCO 中受益。
当您添加日志记录时,它使
runTrace_
不是尾部调用,因此我假设(尽管我不确定具体如何)这必须在某种程度上展开堆栈。
这个版本似乎工作得很好:
runTrace : ComputationModel model state input output -> model -> input -> ( List state, output )
runTrace cm instance input =
let
runTrace_ acc state =
case cm.update instance state of
Err newState ->
runTrace_ (newState :: acc) newState
Ok output ->
( acc, output )
in
runTrace_ [] <| cm.init instance input