Я пытаюсь принять, например. ExceptT a (StateT A M)
, для некоторого конкретного типа A
и монады M
, и заверните их в мои новые монады.Уборка Monads - превращение монадного трансформатора в монумент newtype
Сначала я определил, что StateT A M
часто появляется и в других контекстах, и, таким образом, я решил, что было бы лучше, чтобы обернуть, что только в монады M1
и затем обернуть ExceptT a M1
в M2
.
Желаемое свойство сделать M1
и M2
экземпляры MonadState
и класс M
(позволяет предположить, что это называется MyMonadClass
). Также M2
должен быть экземпляром MonadError
.
Сначала я простые синонимы типа:
type MyState = StateT A M
type MyBranch a = ExceptT a MyState
тогда я думал, что я первый набросок декларации экземпляра (без реализации экземпляра) и то, где я первый застрявших. instance MonadState A (MyState)
, казалось, не был правильным синтаксисом. Я думал, что мне нужно будет создать newtype MyState' a = StateT a M
, а затем type MyState = MyState A
(Не рекомендуется использовать языковые расширения там, где это необходимо).
Однако, как только я начал преобразовывать синонимы в объявления newtype
, я начал терять соединение с типами StateT A M
и ExceptT ...
.
newtype MyState' s a = MyState' { runMyState :: s -> (s, a) }
type MyState = MyState' A
newtype MyBranch e a = MyBranch { runMyBranch :: MyState (Either e a) }
Теперь трансформаторы, которые уже реализованы исчезнувшего, и я думаю, что я пытаюсь сделать что-то, что не имеет особого смысла. Поэтому я задаюсь вопросом: как правильно перенести такое поведение в новые составные монады, которые делают доступными слои под ними, чтобы избежать ненужного подъема и держать вещи ясными и хорошо организованными.
Большое спасибо, это отличный ответ. Могу ли я как-то обойтись без языковых расширений, таких как 'GeneralizedNewtypeDeriving'? – jakubdaniel
@JakubDaniel Конечно, вы можете написать все экземпляры вручную. Но вы не хотите (и, вероятно, повредите), таким образом, «GeneralizedNewtypeDeriving». – Cirdec
Чтобы увидеть фактический код, который выводит выполнение команды ': set -ddump-deriv' в GHCi, он показывает вам весь код, который GHC щедро пишет для вас. 'данные AB = A | B, вызывая Eq 'dumps' instance GHC.Classes.Eq Ghci5.AB где (GHC.Classes. ==) Ghci5.A Ghci5.A = GHC.Types.True; (GHC.Classes. ==) Ghci5.B Ghci5.B = GHC.Types.True; (GHC.Classes. ==) _ _ = GHC.Types.False' –