首页 > 解决方案 > 如何在 Haskell 中调试变量/递归数据类型

问题描述

https://www.inf.ed.ac.uk/teaching/courses/inf1/fp/exams/exam-2016-paper1-answers.pdf

-- 3b
trace :: Command -> State -> [State]
trace Nil s = [s]
trace (com :#: mov) s = t ++ [state mov (last t)]
where t = trace com s

我很难理解第 3b 节。我尝试一一调试变量,但我总是以违反定义的数据类型而告终。代码让我感到困惑,我想看看变量包含什么。我怎样才能使用 Debug.Trace 来做到这一点?

https://downloads.haskell.org/~ghc/latest/docs/html/libraries/base-4.12.0.0/Debug-Trace.html

谢谢你。

标签: debugginghaskellrecursionfunctional-programming

解决方案


看起来第 3b 节正在教授“递归的工作原理”这些幻灯片仅涵盖传统的 Haskell 列表。你所拥有的:#:是相反的,有时称为snoc列表。然后一个明智的设计trace是也产生一个snoc列表结果。但事实并非如此(可能是因为讲师认为通过这样折磨初学者,他们会学到一些东西)。Haskell 列表推导仅适用于列表,不适用于snoc. (那么这些幻灯片中的一半内容对于这个练习是无用的。)所以 3b 正在通过递归教你结构反转(这是幻灯片中有用的一半)。

违反定义的数据类型

您提供的代码中的变量t是函数的本地变量trace,因此似乎难以访问。但它的定义

t = trace com s

不是:

  • 我们知道trace :: Command -> State -> [State]
  • 我们可以在等式中t看到trace它适用于两个参数。
  • 所以 的类型t必须是 的结果的类型trace,即[State]

您不确定trace等式中参数的类型是什么t?特别是comCommand论点解压缩到trace顶层。

  • 然后我们需要了解:#:. 我们有问题 3

    data Command =
         Nil
       | Command :#: Move
    
  • 这就是(:#:)一个中缀运算符(这就是我把它放在括号中的原因)。

  • 然后我们可以向 GHCi 询问它的类型,以确保。
  • 使用:type命令,确保放置括号。
  • 作为对比,还需要:type通常的 Haskell List constructor(:)的 —— 见左右反转?

  • 左边的项(:#:)是类型Command

  • 那么com等式中的变量 fort必须是 type Command; 这符合呼叫trace的预期。

推荐阅读