У меня есть код, который в настоящее время использует монаду ST для оценки.Мне нравится не помещать IO везде, потому что метод runST
дает чистый результат и указывает, что такой результат безопасно вызывать (по сравнению с unsafePerformIO
).Однако, поскольку часть моего кода стала длиннее, я хочу добавить отладочные операторы печати.
Есть ли какой-нибудь класс, который предоставляет монаду с двумя личностями [или механизм типов классов], который может быть STили IO (в зависимости от его типа или флага "isDebug")?Я помню, что SPJ представил класс "Mutation" в своей статье "Fun with Type Functions", в которой использовались ассоциативные типы для связи IO с IORef и ST с STRef.Существует ли такое где-нибудь как пакет?
Редактировать / Решение
Большое спасибо [в девятый раз], CA McCann!Используя это решение, я смог представить дополнительный класс для монад, которые поддерживают функцию pdebug
.Монада ST
будет игнорировать эти вызовы, тогда как IO
будет выполнять putStrLn
.
class DebugMonad m where
pdebug :: String -> m ()
instance DebugMonad (ST s) where
pdebug _ = return ()
instance DebugMonad IO where
pdebug = putStrLn
test initV = do
v <- newRef initV
modifyRef v (+1)
pdebug "debug"
readRef v
testR v = runST $ test v
Это имеет очень удачное последствие в ghci.Так как он ожидает, что выражения будут типами ввода-вывода по умолчанию, запуск чего-то вроде «test 3» приведет к запуску монады ввода-вывода, так что вы можете легко отладить его, а затем вызвать его с чем-то вроде «testR», когда вы действительно хотите запуститьэто.