Я скручиваю свой мозг в узлы, пытаясь понять, как соединить монаду State
с Maybe
.
Давайте начнем с конкретного (и намеренно тривиального/ненужного) примера, в котором мы используем монаду State
для нахождения суммы списка чисел:
import Control.Monad.State
list :: [Int]
list = [1,4,5,6,7,0,3,2,1]
adder :: Int
adder = evalState addState list
addState :: State [Int] Int
addState = do
ms <- get
case ms of
[] -> return 0
(x:xs) -> put xs >> fmap (+x) addState
Прохладно.
Теперь давайте изменим его так, чтобы он возвращал Nothing
, если список содержит число 0
. Другими словами, evalState addState' list
должно возвращать Nothing
(поскольку list
содержит 0
). Я думал, что это может выглядеть примерно так...
addState' :: State [Int] (Maybe Int)
addState' = do
ms <- get
case ms of
[] -> return (Just 0)
(0:xs) -> return Nothing
(x:xs) -> put xs >> fmap (fmap (+x)) addState'
... это работает, но я предполагаю, что есть лучший способ сделать это...
Я играл с StateT
и MaybeT
и не могу заставить их работать. Я просмотрел пару вступлений к трансформерам Monad, но они либо не затрагивали эту конкретную комбинацию (т. е. State + Maybe), либо примеры были слишком сложными для моего понимания.
TL;DR: Буду признателен, если кто-нибудь покажет, как написать этот (по общему признанию тривиальный) фрагмент кода, используя StateT
и MaybeT
(два примера). (Я предполагаю, что невозможно написать этот код без использования трансформаторов — это неверно?)
P.S. Насколько я понимаю, StateT
, вероятно, лучше подходит для этого примера, но концептуально было бы полезно увидеть оба примера, если не слишком много проблем.
Обновление: Как указал @Brenton Alker, моя первая версия приведенного выше кода не работает из-за простой опечатки (мне не хватало апострофа). Чтобы сфокусировать вопрос на использовании StateT
/MaybeT
, я исправляю сообщение выше. Просто хотел включить эту заметку, чтобы придать контекст своему сообщению.