失败块

失败块允许用户检查某些代码虽然能通过解析但在细化阶段被拒绝。其最简单的形式是使用关键字 failing 后跟一些缩进的 Idris 代码:

failing
  trueNotFalse : True === False
  trueNotFalse = Refl

将上述代码放入文件并让 Idris 检查它不会产生错误消息,因为 failing 块中的代码被拒绝了,即失败了。

failing 关键字可以选择性地接受一个字符串参数。如果提供了该参数,附加到失败块的字符串将与产生的错误消息进行比对,以检查它是否出现在错误中。这使用户可以记录块中预期的错误类型,同时验证错误消息确实符合我们的预期。例如,在下面的例子中,我们确保 Idris 在统一字符 'a''b' 时抛出错误,从而拒绝它们相等的证明:

failing "When unifying"
  noteq : 'a' === 'b'
  noteq = Refl

失败块在演示程序或示例中的错误路径或起点时很有用。失败块中允许使用有效的代码,因此只要块中至少有一个语句失败(不必是第一个或最后一个语句!),就可以使用中间辅助函数:

failing "Mismatch between: Integer and Double"
  record Point where
    constructor MkPoint
    x : Integer
    y : Integer

  Origin : Point
  Origin = MkPoint 0 0

  dist : Point -> Point -> Integer
  dist p1 p2 = sqrt $ (pow (p2.x - p1.x) 2) + (pow (p2.y - p1.y) 2)

无效的失败块

如果失败块没有失败,即其中的代码在细化阶段被接受,编译器将报告错误:

failing
  validRefl : 1 === 1
  validRefl = Refl

检查上述代码会得到:

Error: Failing block did not fail.

同样,如果提供了预期的错误(子)字符串但错误输出不匹配,我们会得到:

Error: Failing block failed with the wrong error.

后面跟着给定的预期错误字符串和实际的错误输出,允许我们进行比较和对比。

每个错误一个块

注意为每个要检查的内容使用单独的 ``failing`` 块。 使用单个块可能导致意外结果。以下示例通过,因为第二个语句失败:

failing
  stmt1 : True === True
  stmt1 = Refl

  -- at least one failing statement, so the block is accepted
  stmt2 : 'a' === 'b'
  stmt2 = Refl

  stmt3 : 1 === 1
  stmt3 = Refl

相反,将语句分离到单独的失败块中:

failing
  stmt1 : True === True
  stmt1 = Refl

failing
  stmt2 : 'a' === 'b'
  stmt2 = Refl

failing
  stmt3 : 1 === 1
  stmt3 = Refl

这会发出两个 Error: Failing block did not fail 消息,正如预期的那样。