【问题标题】:Make GHC ignore not-in-scope errors让 GHC 忽略不在范围内的错误
【发布时间】:2015-03-23 12:54:33
【问题描述】:

我正在构建一个模块,每次我编写一个函数时,它都会调用十几个尚不存在的其他函数。显然它们最终会存在,但如果能够在我写完代码之前进行语法检查,那就太好了。

我可以使用一些标志组合来使 GHC 发出警告而不是“名称 foo 不在范围内”的错误吗?

(实际上,如果 GHC 可以为不存在的名称选择一个类型签名,并确认程序仍然可以进行类型检查,那就太好了。这 几乎 “类型孔”功能可以 - 但要使用它,您仍然必须手动定义所有标识符。)

【问题讨论】:

  • 我敢说,为此类功能写出签名和= undefined 是一种很好的做法......但是,好问题,我有时也想要这样的想法,因为我不是确保值得尝试让它们进行类型检查,因为它甚至可能无法解析。
  • 另一种检查语法是否正确的方法是使用pointfree 之类的东西并检查“解析错误:EOF”,但这使得除了单行之外的任何事情都很难做表达。
  • @leftaroundabout 就我而言,我正在构建一个解析器。这意味着有 数百个 不存在的标识符,所有这些都应该是解析器。当我最终完成所有作品的编写时,它应该可以工作。但是在我结束之前发现语法错误会很好......
  • 我会关注@leftaroundabout 的类型签名+未定义的方法。我一直在使用它。如果您愿意,您甚至可以跳过类型签名,让变量完全多态,但是您可以添加的类型签名越多,您的类型错误消息可能就越好。
  • @leftaroundabout 我假设 OP 的真正意思是“语法和类型检查”。如果您真的只需要语法检查,则无需定义所有内容 - 超出范围错误意味着模块必须首先正确解析。

标签: haskell ghc


【解决方案1】:

使用命名TypedHoles

> let f x = _g . _h x $ x
    Found hole ‘_g’ with type: b0 -> c
    Where: ‘b0’ is an ambiguous type variable
           ‘c’ is a rigid type variable bound by
               the inferred type of f :: s -> c at <interactive>:2:5
    Relevant bindings include
      x :: s (bound at <interactive>:2:7)
      f :: s -> c (bound at <interactive>:2:5)
    In the first argument of ‘(.)’, namely ‘_g’
    In the expression: _g . _h x
    In the expression: _g . _h x $ x

    Found hole ‘_h’ with type: s -> s -> b0
    Where: ‘b0’ is an ambiguous type variable
           ‘s’ is a rigid type variable bound by
               the inferred type of f :: s -> c at <interactive>:2:5
    Relevant bindings include
      x :: s (bound at <interactive>:2:7)
      f :: s -> c (bound at <interactive>:2:5)
    In the expression: _h
    In the second argument of ‘(.)’, namely ‘_h x’
    In the expression: _g . _h x

所以这会给你_g :: b0 -&gt; c_h :: s -&gt; s -&gt; b0 以及x :: sf :: s -&gt; c 的上下文。类型检查器大部分时间都可以推断出这些类型(这是TypedHoles 的重点),您可以给它们命名。如果需要,您可以使用_ 作为符号名称的第一个字符来定义所有函数,然后使用您的编辑器将_(.+)\b 替换为\1。如果您想解决使用_name 作为记录字段的镜头约定,那么只需在您的孔名称上加上 2 个下划线。

这仍然会阻止您的代码编译,但如果您将其与 -fdefer-type-errors 结合使用,它们将被报告为警告,从而允许您在运行时发生类型错误。

【讨论】:

  • 所以你是说如果我只是用下划线开始所有标识符并打开-fdefer-type-errors,我会得到我想要的大致行为?
  • @MathematicalOrchid 或多或少,如果我理解你想要什么。您的标识符只需以_ 开头即可使其成为一个洞,GHC 会推断出该洞的类型,GHC 通常会为其发出编译错误,但-fdefer-type-errors 会将这些错误转化为警告,因此您甚至可以将程序运行到出现孔的点,因此let f = putStrLn "test" &gt;&gt; _foo; f 将打印test 然后显示一个异常,其中包含您在没有-fdefer-type-errors 的情况下在编译时会得到的确切错误消息。
  • @MathematicalOrchid 正如 dfeuer 和 leftaroundabout 所指出的那样,使用类型签名和 undefined 定义它们不需要任何额外的标志来编译,并且会改进错误消息并确保您的表达式具有所需的类型,而不是仅仅为了进行类型检查所需的任何类型。我想你可以为 编写一个插件,它可以从带有error "hole name" 和推断类型签名的表达式中提取一个命名的孔,然后使用“提取所有”命令将这些孔分解出来将是一件轻而易举的事。跨度>
【解决方案2】:

我通常的做法是将缺失的函数或值定义为undefined。它很容易定义,并为您留下一个方便的标记,表明所讨论的函数尚未定义。

我知道这并不能回答 OP 的问题,因为这些功能仍然必须手动定义,但我认为它还是有用的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-06
    • 1970-01-01
    相关资源
    最近更新 更多