Хаскель рекламируется как язык в котором чистые функции отделены от IO actions. При этом, как я это понимаю, функции работающие в остальных монадах все равно остаются частью чистого кода. И если мы возьмем монад трансформер Q, вычисления типа Q a m b где m монада которая не инстанс MonadIO, то мы тоже легко можем запускать на этом коде QuickCheck и доказывать о нем разнообразные факты.
Но если для монады определен liftIO, то что же получается, опять все в кучу? Дискасс.