Вот немного примера кода
foo :: a -> Identity (Maybe a)
foo a = do
maybeStuff <- getStuffSometimes a
return $ case maybeStuff of -- this "case" stuff is the kind
Just stuff -> Just $ getStuffAlways stuff -- of code I'd expect the Maybe
Nothing -> Nothing -- monad to help with
getStuffSometimes :: a -> Identity (Maybe a)
getStuffSometimes a = return $ Just a
getStuffAlways :: a -> Identity a
getStuffAlways = return
-- ERROR (on the return statement of the do block)
-- Expected type: Identity (Maybe a)
-- Actual type: Identity (Maybe (Identity a))
Может быть немного неясно, что я пытаюсь сделать, поэтому вот более подробное описание:
Все самое интересное заключено в вычислительный контекст/контейнер — в данном случае
Identity
для демонстрации. В моем реальном коде у меня, конечно, есть еще одна монада.Предполагается, что
foo
иgetStuffSometimes
принимают что-то типаa
и возвращаютMaybe a
, завернутый в контекст, то есть они возвращают либоIdentity (Just a)
(вычисление выполнено успешно, либоIdentity Nothing
(вычисление не выполнено).getStuffAlways
— это вычисление, которое никогда не дает сбоев — оно всегда возвращаетIdentity a
.Я хочу, чтобы
foo
:- Run a failable computation
- Если неудавшееся вычисление завершается ошибкой, завершается ошибкой (без ничего)
- Если ошибочное вычисление завершилось успешно, свяжите его с помощью getStuffAlways и верните
Just (result of getStuffAlways to the result of #1)
Является ли это вариантом использования Monad Transformers? В моем случае моя фактическая монада немного сложна и представляет собой стек нескольких преобразователей, предоставленных моей библиотекой поверх IO, и я не совсем уверен, как заставить ее работать в этой ситуации (я бы задал ее в другом вопросе в итоге приходится использовать трансформаторы)
Следовать за:
В реальной жизни у меня есть что-то вроде:
foo :: a -> Identity (a, Maybe a)
foo a = do
firstPart <- getStuffAlways a
maybeStuff <- getStuffSometimes a
secondPart <- case maybeStuff of
Just stuff -> Just $ getStuffAlways stuff
Nothing -> Nothing
return (firstPart, secondPart)
Как лучше построить стек в этом случае?