Нет
Функция в монаде состояния, такая как a -> State s b
, - это чистая функция (без ввода-вывода), в которой есть дополнительный аргумент функции s
, хотя она скрытанемного удобной сантехники.
Вы не можете печатать на консоли из монады состояния.
Однако, да!
Однако!Вы можете использовать монаду преобразователь , чтобы получить как State, так и некоторую базовую монаду, такую как IO.
Я приведу пример использования transformers
вместо пользовательской монады и mtl
в качествеПохоже, вы использовали.С mtl
вы можете использовать классы типа MonadError
для использования throw
, который хорошо работает с другими библиотеками, которые используют классы mtl.С другой стороны, если вы являетесь конечным потребителем этого преобразователя, это менее важно.
Сначала мы импортируем модули, которые дают нам MonadIO, StateT, MaybeT, и используем вывод новых типов, поэтому мы не будемнужно набрать шаблон экземпляра монады:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import qualified Control.Monad.Trans.State as S
import Control.Monad.IO.Class
import Control.Monad.Trans.Maybe
import Control.Monad.Trans
Просто чтобы завершить, мы изложим типы, полезные для вашей абстракции:
type Variable = String
type Env = [(Variable,Int)]
Теперь мы можем перейти к интересномучасть - определение монады и функции для сантехники.Стек монады - StateT MaybeT IO:
newtype StateError a = StateError { unStateError :: S.StateT Env (MaybeT IO) a }
deriving (Monad, Applicative, Functor)
И мы можем запустить его, сначала развернув новый тип, затем запустив состояние, и, наконец, MaybeT:
run :: StateError a -> IO (Maybe (a, Env))
run = runMaybeT . flip S.runStateT [] . unStateError
Обычно вы 'Я напишу армию функций, которые обеспечат вашу абстракцию монады.Для этого вопроса это просто «обновить состояние» и «напечатать на стандартный вывод»:
modify :: (Env -> Env) -> StateError ()
modify = StateError . S.modify
emit :: Show a => a -> StateError ()
emit = StateError . liftIO . print . show
Вооружившись нашей Монадой Силы, мы можем сделать такие причудливые вещи, как состояние обновления и emit IOсообщения и отслеживают сбой или успех:
updateAndPrint :: Variable -> Int -> StateError ()
updateAndPrint v i =
do emit (v,i)
modify ((v,i):)
О, и сбой довольно прост - просто потерпите неудачу в нашей MaybeT
монаде:
throw :: a -> StateError b
throw _ = fail "" -- same as 'MaybeT (pure Nothing)'
Мы можемиспользуйте эту монаду как положено:
> run $ updateAndPrint "var" 1
"(\"var\",1)"
Just (() -- ^ return value of `updateAndPrint`
,[("var",1)]) -- ^ resulting state