intellij中的haskell调试插件

时间:2018-01-11 14:00:43

标签: 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正常调试似乎太复杂了。

1 个答案:

答案 0 :(得分:11)

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 = []

请注意,我只是将值绑定到GHCi中的符号xyrest。这使您可以评估函数中where块中的第一个表达式:

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]

如果您需要提醒一下结果的原因,您甚至可以检查secondrestsecond: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中的值重新绑定到例如完成案例[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有一个更好的长期理解,而不是试图让调试器工作。