sinoTrinity
sinoTrinity

Reputation: 1195

assert is not evaluated in return ()

I have the following code snippet, where assert is used to check an invariant regarding some internal state. However, assert is never evaluated and thus never fails even when it should, probably because return is not evaluated when returning type (). This holds even if I change to assert False. Any way to fix this?

FooM :: m () // m is a monad
FooM = do
  state <- get
  // some state mutation
  state' <- get
  return $ assert (state /= state') ()
  return $ assert False () // <-- this also never fails

Upvotes: 0

Views: 82

Answers (1)

HTNW
HTNW

Reputation: 29193

return $ assert (state /= state') () is evaluated, because the monadic >>= needs to evaluate it to figure out "what to execute" (it just so happens that that is "nothing"). But though the action is evaluated, the value assert (state /= state') () contained in that action is not, because it isn't used. The solution is to guard the action return () with assert, not the (ignored) value ().

assert (state /= state') $ return ()

Alternatively,

return $! assert (state /= state') ()
-- = let arg = assert (state /= state') () in arg `seq` return arg
-- for evaluation to "get to" the return, the assertion must succeed

Upvotes: 3

Related Questions