Интуиция для MaybeT
Я пытаюсь понять MaybeT
запустив несколько примеров в ghci
:
λ: import Control.Monad.Trans.Maybe
λ: let x = return $ 42 :: MaybeT (Either String) Int
λ: :t x
x :: MaybeT (Either String) Int
Затем я запустил его:
λ: runMaybeT x
Right (Just 42)
Пожалуйста, оцените меня, y
такой, что
runMaybeT y === Left (Just "...")
runMaybeT y === Left Nothing
runMaybeT y === Right Nothing
2 ответа
Вы никогда не получите Left Nothing
или же Left (Just ..)
Монада здесь Either String …
, так что слева у вас всегда будет String
,
Вот что вы можете получить:
> let y = fail "Failed" :: MaybeT (Either String) Int
> runMaybeT y
Right Nothing
> let y = lift (Left "Failed") :: MaybeT (Either String) Int
> runMaybeT y
Left "Failed"
Это может помочь понять, что происходит под капотом с MaybeT...
В монаде IO есть вычисления, например
putStrLn "Hello, world!" :: IO ()
getContents :: IO String
и т.д. Все эти вычисления имеют тип IO a
и на самом деле переменная типа a
неограниченно - это может быть любой тип. С помощью return
мы можем создать вычисление IO IO a
для любого типа a
,
Вы можете думать о MaybeT IO
как те вычисления IO, которые возвращают значение Maybe.
Например, getContents
является IO
расчет, но не MaybeT IO
вычисление. Тем не менее, есть своего рода очевидный способ конвертировать getContents
в MaybeT IO
вычисление - просто оберните его вывод в Just
конструктор:
lift getContents === fmap Just getContents
lift
это способ продвижения IO
вычисление в MaybeT IO
вычисление. Применяя это к return_IO
(return
функция для IO
монада) имеем:
return_(MaybeT IO) === lift return_IO === fmap Just return_IO
То есть, return 3
(в MaybeT IO
монада) такая же как return (Just 3)
в IO
монада.
runMaybeT и MaybeT являются противоположностями друг друга
Теперь посмотрим на определение MaybeT
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
Это также описывает идею о том, что вычисления в MaybeT m
такие же, как вычисления в m
которые возвращают значение Maybe. Функции:
MaybeT :: m (Maybe a) -> MaybeT m a
runMaybeT :: MaybeT m a -> m (Maybe a)
являются противоположностями друг друга и на самом деле ничего не делают, кроме добавления или удаления оболочки нового типа. В случае с IO
монада:
MaybeT :: IO (Maybe a) -> MaybeT IO a
runMaybeT :: MaybeT IO a -> IO (Maybe a)
Рассматривая пример в вашем вопросе, мы видим, что вычисления в MaybeT (Either String)
по существу такие же, как значения типа Either String (Maybe a)
для любого типа a
, Это приводит к следующим возможностям:
Left
какой-то строкиRight (Just ...)
Right Nothing
Все это существует в Either String (Maybe a)
и если мы применим конструктор MaybeT
для каждого из них мы получаем соответствующие значения в MaybeT (Either String) a
,
В частности, чтобы найти y
улица
runMaybeT y == Right Nothing
просто используйте:
y = MaybeT (Right Nothing)
Снова, runMaybeT
а также MaybeT
являются противоположностями друг друга, поэтому вы можете получить тот же результат, применяя MaybeT
в обе стороны.