How is assert used?

Viewed 2571

I'm having trouble understanding how to use the assert function (Control.Exception.Assert)

I did read the documentation (http://hackage.haskell.org/package/assert-0.0.1.2/docs/Control-Exception-Assert.html) but I still don't seem to understand how it's used. The currying really doesn't help in this case because of how unexplicit it is. Examples and explanation of what it's for would be lovely.

(For context, I am trying to figure out how to use assert in this code to make sure n is always non-negative) [No answers please, I'd like to figure it out on my own]

power :: Int -> Int -> Int
power x n =
  if n == 0 then
    1
  else
    x * power x (n - 1)
2 Answers

The assert exported from that library (which I haven't used) is actually defined in base here. You could use it like this:

power :: Int -> Int -> Int
power x n = assert (n >= 0) $
  if n == 0 then
    1
  else
    x * power x (n - 1)

But this isn't really what the function is meant for. It would be better in the case above to either raise your own error with a friendly message, or (better yet), return a Maybe Int.

assert is intended for checking internal invariants in your functions, where a violation indicates a bug. It can be really useful to use assertions in tandem with tests (tests excercise invariants which are checked by internal assert calls).

You have to make sure to compile either without optimizations or with -fno-ignore-asserts though, as assertions are optimized away when compiling with optimizations (another great feature of assert).

I've taken to including the following in the library code in order to have a test that assertions are on in my testsuite (very important, and an issue I've run into before):

assertionCanary :: IO Bool
assertionCanary = do
    assertionsWorking <- try $ assert False $ return ()
    return $
      case assertionsWorking of
           Left (AssertionFailed _) -> True
           _                        -> False

Think of assert as a conditional identity function. If the first argument is false, an exception is raised. Otherwise, the second argument is returned. An implementation might look something like

assert :: Bool -> a -> a
assert True = id
assert False = \_ -> error "Assertion Failed"  -- const (error "Assertion Failed")

(I'm not sure what example of its use to give that wouldn't effectively give away how to write power.

Related