Я думал, что в принципе система типа haskell запретит вызывать нечистые функции (т.е. f :: a -> IO b) из чистых, но сегодня я понял, что, называя их с помощью return, они компилируются просто отлично. В примере:
h :: Maybe ()
h = do
    return $ putStrLn "???"
    return ()
Теперь h работает в возможно монаде, но это чистая функция. Компиляция и запуск этого метода просто возвращает Just (), как и следовало ожидать, без ввода каких-либо операций ввода-вывода. Я думаю, что haskell лень объединяет вещи (т.е. putStrLn возвращаемое значение не используется - и не может, поскольку его конструкторы значений скрыты, и я не могу сопоставить их с ним), но почему этот код является законным? Существуют ли другие причины, позволяющие это разрешить?
В качестве бонуса, связанный с ним вопрос: вообще, можно ли вообще запретить исполнение действий монады изнутри других? Как?