Может ли быть mtl-подобный механизм для монадных трансформаторов, созданных FreeT/ProgramT?
Мое понимание истории таково. Когда-то был изобретен монадный трансформатор. Затем люди начали складывать моноданные трансформаторы друг на друга, а затем находили раздражающим вставлять lift
всюду. Затем несколько человек придумали монадские классы, чтобы мы могли, например, ask :: m r
в любой монаде m
такой, что MonadReader r m
. Это стало возможным благодаря тому, что каждый монадный класс проникал в каждый монадный трансформатор, например,
(Monoid w, MonadState s m) => MonadState s (WriterT w m)
MonadWriter w m => MonadWriter w (StateT s m)
вам нужна такая пара описаний экземпляров для каждой пары монадных трансформаторов, поэтому при наличии n монадных трансформаторов n ^ 2 стоит. Однако это была не большая проблема, потому что люди будут в основном использовать предопределенные монады и редко создавать свои собственные. История до сих пор я понимаю, а также подробно, например. в следующих Q & A:
Избежать подъема с помощью трансформаторов Monad
Тогда моя проблема связана с новыми Free monads http://hackage.haskell.org/package/free и операционными монадами http://hackage.haskell.org/package/operational. Они позволяют нам писать собственный DSL и использовать его в качестве монадов, просто определяя язык как некоторый алгебраический тип data
(операционным даже не нужны экземпляры Functor
). Хорошая новость заключается в том, что у нас могут быть монады и монадные трансформаторы бесплатно; то как насчет монадских классов? Плохая новость заключается в том, что предположение "мы редко определяем наши собственные монадные трансформаторы" больше не выполняется.
Как попытка понять эту проблему, я сделал два ProgramT
и сделал их проникающими друг в друга;
https://github.com/nushio3/practice/blob/master/operational/exe-src/test-05.hs
Пакет operational
не поддерживает monad-классы, поэтому я сделал еще одну реализацию minioperational
и модифицировал ее для работы, поскольку мне нужно; https://github.com/nushio3/minioperational
Тем не менее, мне понадобилось объявление специализированного экземпляра
instance (Monad m, Operational ILang m) => Operational ILang (ProgramT SLang m) where
потому что общее объявление следующей формы приводит к неразрешимым экземплярам.
instance (Monad m, Operational f m) => Operational f (ProgramT g m) where
Мой вопрос заключается в том, как мы можем облегчить проникновение наших операционных монадов друг в друга. Или мое желание проникнуть в любую рабочую монаду некорректно.
Я также хотел бы знать правильный технический термин для проникновения:)