Если вы хотите использовать утверждения в стандартном коде Haskell, можно определить функцию, подобную следующей:
assert :: Bool -> a -> a assert False x = error "assertion failed!" assert _ x = x
Она работает, но возвращает малополезное сообщение об ошибке: утверждение не выполнено, но какое именно и где?
Один из способов решить эту проблему — определить расширенную функцию assert, которая также принимает описательную строку для включения в сообщение об ошибке, и, возможно, объединить это с использованием препроцессора, вставляющего расположение в исходном коде, где использовалось assert.
GHC помогает решить эту задачу, выполняя всё это за вас. Для каждого использования assert в исходном коде пользователя:
kelvinToC :: Double -> Double kelvinToC k = assert (k >= 0.0) (k-273.15)
GHC перепишет это выражение, добавив расположение в исходном коде, где было сделано утверждение,
assert pred val ==> assertError "Main.hs|15" pred val
Переписывание выполняется компилятором только при обнаружении вызовов Control.Exception.assert, поэтому при желании вы по-прежнему можете определять и использовать собственные версии assert. Если это не так, импортируйте Control.Exception, чтобы использовать assert в коде.
GHC игнорирует утверждения, когда включена оптимизация с флагом -O. То есть выражения вида assert pred e будут переписаны в e. Также можно отключить утверждения с помощью параметра -fignore-asserts. Параметр -fno-ignore-asserts позволяет включить утверждения, даже когда включена оптимизация.
Сбои утверждений можно перехватывать; подробности см. в документации библиотеки Control.Exception.
6.19.5. Макрос CPP __GLASGOW_HASKELL_ASSERTS_IGNORED__
Когда код компилируется с игнорированием утверждений (с использованием -fignore-asserts или -O), будет определён макрос CPP __GLASGOW_HASKELL_ASSERTS_IGNORED__. Его можно использовать для условной компиляции собственных функций, подобных assert. Например:
checkedAdd :: Word -> Word -> Word
#ifdef __GLASGOW_HASKELL_ASSERTS_IGNORED__
checkedAdd lhs rhs = lhs + rhs
#else
checkedAdd lhs rhs
| res < lhs || res < rhs = raise OverflowException
| otherwise = res
where res = lhs + rhs
#endif