debugging - intellij中的haskell调试插件

标签 debugging haskell intellij-idea

bubblesort2 :: (Ord a, Show a) => [a] -> [a]
bubblesort2 [] = []
bubblesort2 [x] = [x]
bubblesort2 (x:y:rest) =
    bubblesort2 (init bubbled) ++ [last bubbled]
    where
        (first,second) = if x > y then (y,x) else (x,y)
        bubbled = first : bubblesort2(second:rest)

我试图理解上面的haskell代码。我尝试在 intellij,jetbrains haskell 插件中调试代码,但由于某种原因,它会引发调试执行错误。有什么好的方法可以通过 ide 进行调试。通过gchi进行正常调试似乎太复杂了。

最佳答案

FWIW,如果您来自面向对象的背景,您会发现使用函数式编程不需要调试器,这似乎是一种常见的体验。我不知道这是否是你的背景,但这就是我的旅程。在我编写 Haskell 代码的几年中,我从未研究过如何调试它。

我有时必须调试 F# 代码,但仅限于它与 .NET 的面向对象部分交互时。

调试器允许您通过计算检查各个阶段的变量的内部状态。当代码涉及可变状态时这是有道理的,但当一切都是不可变的并且表达式是引用透明时变得不那么重要了。

当我不理解一段 Haskell 代码时,我通常会开始分解它并使用 GHCi 中的各种子表达式。在此特定示例中,您可以执行以下操作。

首先,希望清楚当输入为 [] 时会发生什么。或 [x] :

Prelude> bubblesort2 []
[]
Prelude> bubblesort2 [42]
[42]

我假设您想要理解的代码部分是 bubblesort2 (x:y:rest)案子。那么,我要做的就是从 [] 继续前进。和 [42]到下一个最简单的情况,您恰好有两个值:
Prelude> bubblesort2 [1337,42]
[42,1337]

这对应于 bubblesort2 (x:y:rest)案例,其中:
Prelude> x = 1337
Prelude> y = 42
Prelude> rest = []

请注意,我只是将值绑定(bind)到符号 x , yrest在 GHCi 中。这使您能够计算 where 中的第一个表达式。函数中的 block :
Prelude> (first,second) = if x > y then (y,x) else (x,y)
Prelude> first
42
Prelude> second
1337

接下来你可以运行 bubblesort2(second:rest)子表达式:
Prelude> bubblesort2(second:rest)
[1337]

如果您需要提醒为什么这是结果,您甚至可以检查 second , rest , 和 second:rest :
Prelude> second
1337
Prelude> rest
[]
Prelude> second:rest
[1337]

迟早,您可能会意识到这是 bubblesort2 [x]情况,这就是为什么 bubblesort2(second:rest)返回 [1337] .您现在应该很清楚 bubbled 是什么是,但除此之外,您也可以评估它:
Prelude> bubbled = first : bubblesort2(second:rest)
Prelude> bubbled
[42,1337]

继续,您现在可以开始分解 bubblesort2 的主体了.首先,例如:
Prelude> [last bubbled]
[1337]

和:
Prelude> init bubbled
[42]

所以,再次,bubblesort2 (init bubbled)匹配 bubblesort2 [x]案例,以便您获得:
Prelude> bubblesort2 (init bubbled)
[42]

最后:
Prelude> bubblesort2 (init bubbled) ++ [last bubbled]
[42,1337]

通过这些步骤,您应该能够理解列表恰好包含两个元素的情况。一旦这对您有用,您就可以继续将 GHCi 中的值重新绑定(bind)到例如浏览案例[1337, 42, 12345] :
Prelude> x = 1337
Prelude> y = 42
Prelude> rest = [12345]
Prelude> (x:y:rest)
[1337,42,12345]

我不打算带您完成这个案例,但我希望您能清楚地了解如何以与上述相同的方式完成它。

我想我知道你会说什么:

每次我必须调试时都必须这样做吗?!

根据我的经验,当您开始使用 Haskell 或其他函数式编程语言时,有很多您不理解的地方,并且您会经常感到需要使用调试器。

这只是一个阶段,它会过去的。

在 REPL 中使用代码是一种更惯用的函数式编程方法,一旦你习惯了它,你就会倾向于始终打开一个 REPL。在谈到 Haskell 和 F# 时,这对我来说都是正确的,而且我听到其他函数式程序员也这么说。 Clojure 程序员似乎也是如此。

需要明确的是,这些天来,我很少觉得需要在上面概述的详细级别上单步执行 Haskell 代码。通常,只有一两个我觉得难以理解的表达式,然后我只是将其隔离并在 GHCi 中使用它,直到我理解发生了什么。

我认为,在 GHCi 中解决问题会让你对 Haskell 有更好的长期理解,而不是试图让调试器工作。

关于debugging - intellij中的haskell调试插件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48208827/

上一篇:R包导出ICS?

下一篇:C: 运算符 -> 和 *

相关文章:

java - IntelliJ 中代码的自定义格式

.net - WinDbg 地址汇总

angularjs - Angular $rootScope.on ('$stateChangeStart' ) 不工作

haskell - 带 fclabel 的 STM

java - IntelliJ + JUnit 5(木星)

java - 在IntelliJ IDEA中运行Gradle测试时的"No tests found for given includes"

c++ - 在Eclipse中调试C/C++代码时,如何查看全局变量?

mysql - 是否可以从 MySQL 的事务回滚中排除某些查询/过程?

haskell - 使用回旋镖解析整数列表

haskell - 在 Haskell 中执行 while 循环