Haskell - монада двойного характера IO / ST?
У меня есть код, который в настоящее время использует монаду 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", когда вы действительно хотите запустить Это.
2 ответа
Если вы хотите унифицированный интерфейс для IORef
а также STRef
Вы смотрели на stateref
пакет? Он имеет классы типов для "ссылок на изменяемые данные", разделенных для читаемых, записываемых и т. Д., С экземплярами для IORef
а также STRef
, а также такие вещи, как TVar
, MVar
, ForeignPtr
, так далее.
Вы рассматривали Debug.Trace.trace вместо этого?