如何在 Haskell 中调试无限递归?

Ruf*_*ind 5 debugging profiling haskell

如何使用 GHC 的分析工具调试这个(显然)有缺陷的程序?程序在 的第二个子句中输入无限递归frobnicate

-- Foo.hs
frobnicate :: Show a => Maybe a -> String
frobnicate Nothing = ""
frobnicate x       = case frobnicate x of
  "" -> "X"
  _  -> show x

main :: IO ()
main = print (frobnicate (Just "" :: Maybe String))
Run Code Online (Sandbox Code Playgroud)

这个例子可能看起来很做作,但它实际上是我今天遇到的一个真实错误的精简版本。

在命令式语言中,错误将是显而易见的,因为堆栈跟踪会显示类似的内容frobnicate -> frobnicate -> frobnicate -> ...。但如何在 Haskell 中发现这一点呢? 如何将责任缩小到这一特定职能?

我尝试了类似以下内容:

ghc -fforce-recomp -rtsopts -prof -fprof-auto Foo.hs
./Foo +RTS -M250M -i0.001 -h
hp2ps -c Foo.hp
Run Code Online (Sandbox Code Playgroud)

添加标志-M250M以确保它不会杀死机器,-i0.001增加分析频率以尝试捕获正在发生的溢出(发生得非常快)。

这会产生这个相当无用的情节:

在此输入图像描述

该图中没有明显的溢出。y 轴甚至不超过一兆字节!我在这里做错了什么?