Если вы хотите использовать утверждения в вашем стандартном коде 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. Макрос __GLASGOW_HASKELL_ASSERTS_IGNORED__ CPP
Когда код компилируется с игнорированием утверждений (с использованием -fignore-asserts или -O), макрос CPP __GLASGOW_HASKELL_ASSERTS_IGNORED__ будет определён. Это можно использовать для условной компиляции собственных пользовательских функций, похожих на утверждения. Например:
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