带有简单断言的 Haskell 脚本

时间:2021-04-17 18:52:14

标签: haskell assert

许多书籍和教程都使用能够断言的小脚本来解释语言特性。如果所有断言都通过,则该进程的退出代码为 0,如果任何一个断言失败,则该进程的退出代码为非零。例如,在 Python 中:

assert type(int) == type
assert len(list(x for x in range(3))) == 3
assert {'x': 1}['x'] == 1

在 Lua 中:

assert(type(7.299E-3) == "number")
assert(#{10, 20, 30} == 3)
assert(utf8.len("cafés") == 5)

在 Ruby 中,我们可以很好地伪造它:

fail unless 5.send(:abs) == 5
fail unless 5.send('abs') == 5
fail unless 5.abs == 5

但是我在 Haskell 中找不到等价物。当我尝试直接使用 error 时,在此脚本中:

main = do
    { 1 == 1 || error "nope"
    ; 3 == 3 || error "nope"
    ; 8 == 8 || error "nope"
    }

我收到错误

 error:
   • Couldn't match expected type ‘m a0’ with actual type ‘Bool’
   • In a stmt of a 'do' block: 1 == 1 || error "nope"

鉴于 main 的预期类型,这是有道理的。现在我能够通过编写自己的模块来做我想做的事情:

module SimpleAssert (assertAll) where
import Data.List (all)
assertAll assertions =
    if all ((==) True) assertions
        then return "ok"
        else error "Assertion failure"

那我的脚本就比较干净了:

import SimpleAssert (assertAll)
main = do
    assertAll 
        [ 1 == 1
        , 3 == 3
        , 8 == 8
        ]

然而,它不像在其他语言中那样独立(它也没有告诉我实际断言在哪里失败,但我可以接受)。 Haskell 有没有办法在没有外部断言函数的情况下做到这一点?我确实知道 Haskell 中的单元测试,但这也有一些“开销”。也许开销是好的和适当的,也许外部函数是正确的方法,但我很想知道 Haskell 是否支持某种轻量级的方法。这种(轻量级)方式存在吗?

1 个答案:

答案 0 :(得分:4)

不完全确定这是否满足您的需求,但一个简单的选择是使用 unless

main = do
  unless (1 == 1) (error "nope")
  unless (3 == 3) (error "nope")
  unless (8 == 8) (error "nope")

如果您愿意,您当然可以轻松地从中提取出一个单独的“断言”函数。

相关问题