Реализация >>= в новом типе
Позвольте мне начать с задачи, которую я хочу решить, возможно, я иду не в ту сторону. Я использую Snap Framework для игрушечного проекта, и главное, что он работает под Snap
монада. Мне нужно добавить свое состояние над ним. Я использую монадный трансформатор:
type SnapApp a = StateT AppState Snap a
Это определено в модуле, скажем, Base
, Так как он мне нужен в других модулях, я должен его экспортировать:
module Base
( ..
, SnapApp
) where
Это хорошо, но я хочу, чтобы этот модуль не экспортировался SnapApp
является монадой состояния, потому что у меня есть сложная обработка для установки некоторых атрибутов для состояния. Например, сессия. Я должен написать файл, когда он будет изменен, поэтому неправильно просто get
и тогда put
модифицированный сеанс, должна быть вызвана специальная функция. Итак, я скрываю, что с помощью newtype
а не экспортер данных констестор:
newtype SnapApp a = SnapApp (StateT AppState Snap a)
Я сделал это экземпляром моего класса с функциями для изменения сессии и т. Д. Но возникает проблема: я потерял экземпляры Monad
класс и прочее для новых SnapApp
, И я застрял с реализацией >>=
:
instance Monad SnapApp where
return = SnapApp . return
mx >>= fm = -- HOW?
Спасибо!
2 ответа
Пусть типы направляют вас. Тебе нужно
(>>=) :: SnapApp a -> (a -> SnapApp b) -> SnapApp b
У тебя есть
(>>=) :: StateT AppState Snap a -> (a -> StateT AppState Snap b) -> StateT AppState Snap b
Вам необходимо конвертировать:
- аргумент
SnapApp a
вStateT AppState Snap a
- аргумент
a -> SnapApp b
вa -> StateT AppState Snap b
- результат
StateT AppState Snap b
вSnapApp b
1) использовать сопоставление с образцом; определить:
fromSnapApp (SnapApp x) = x
2) Составьте функции a -> SnapApp b
а также SnapApp b -> StateT AppState b
3) Использование SnapApp
Конечный результат:
x >>= f = SnapApp (fromSnapApp x >>= (fromSnapApp . f))
или же:
SnapApp x >>= f = SnapApp (x >>= (fromSnapApp . f))
Вам не нужно писать это; GHC может получить экземпляр, если вы включите GeneralizedNewtypeDeriving
расширение:
newtype SnapApp a = SnapApp (StateT AppState Snap a) deriving (Monad)
Это управление состоянием - именно то, что мы разработали для вас. Наша монада Handler на самом деле является просто оболочкой нового типа StateT s Snap
с несколькими дополнительными вещами, встроенными для удобства. Мы раскрываем экземпляр MonadState, чего вы пытаетесь избежать, но вы можете справиться с этим, инкапсулировав тип вашего состояния в модуль и не экспортируя для него никакие методы доступа. Вы можете экспортировать только нужные функции-обработчики, которые выполняют всю сложную обработку атрибутов.