Ray Toal
Ray Toal

Reputation: 88378

Haskell scripts with simple asserts

Many books and tutorials explain language features with small scripts that do asserts. If all the assertions pass, the process has an exit code of 0, and if any one fails, the process has a non-zero exit code. For example, in Python:

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

and in Lua:

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

In Ruby we can fake it in a nice way:

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

But I'm having trouble finding the equivalent in Haskell. When I tried to use error directly, in this script:

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

I get the error

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

which makes sense given the expected type of main. Now I was able to do what I wanted by writing my own module on the side:

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

Then my script is the relatively clean:

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

However it not as stand-alone as in the other languages (nor does it give me any indication of where the actual assertion failed, but I can live with that). Is there a way in Haskell to do without the external assert function? I do know about unit tests in Haskell, but that too has some "overhead." Perhaps the overhead is fine and proper, and maybe an external function is the right way to go, but I'm interested to know if Haskell supports some kind of lightweight approach to this. Does such a (lightweight) way exist?

Upvotes: 0

Views: 388

Answers (1)

Robin Zigmond
Robin Zigmond

Reputation: 18249

Not fully sure if this meets your needs, but one simple option is to use unless:

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

and you could of course easily factor out a separate "assert" function from this if you want to.

Upvotes: 5

Related Questions