Haskell 个带有简单断言的脚本

Haskell scripts with simple asserts

许多书籍和教程使用执行断言的小脚本来解释语言功能。如果所有断言都通过,则进程的退出代码为 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 是否支持某种轻量级方法。这样的(轻量级)方式存在吗?

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

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

如果你愿意,你当然可以很容易地从中分解出一个单独的“断言”函数。