Есть ли библиотека или typeclass для получения версии трансформатора монады?

В моем текущем проекте я столкнулся с необходимостью превратить различные монады в их трансформаторные аналоги, например.

stateT :: Monad m => State s a -> StateT s m a
stateT stf = StateT $ return . runState stf

Тривиально писать эти служебные функции для монад, которые мне нужны, но мне было интересно, существует ли уже библиотека, содержащая эту функциональность для стандартных монадов, и, возможно, класс стилей, который абстрагирует это преобразование. Что-то вроде

class (Monad f, MonadTrans t) => LiftTrans f t | f -> t where
    liftT :: Monad m => f a -> t m a

( "лифт", вероятно, является неправильным термином для использования здесь, но я не был уверен, что еще назвать его.)

Ответ 1

Отметьте функцию hoist в пакете mmorph.

Его подпись

hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b

Значение, что он может изменить базовую монаду, лежащую в основе трансформатора.

Теперь в пакете trasformers многие "основные" монады реализованы в качестве трансформаторов, применяемых к монаде Identity, например:

type State s = StateT s Identity

Таким образом, мы можем определить следующую функцию (взятую в разделе Обобщая базовые монады в документации mmorph):

import Data.Functor.Identity

generalize :: (Monad m) => Identity a -> m a
generalize m = return (runIdentity m)

и объединить его с подъемником:

hoist generalize :: (Monad m, MFunctor t) => t Identity b -> t m b

Этот метод не будет работать для простых монадов, которые не определены как трансформаторы, применяемые к Identity, как монады Maybe и Either. Вы застряли в hoistMaybe и hoistEither для это.

Ответ 2

Вы пытаетесь пойти не так. Если что-то является трансформатором, чем простая версия, это трансформатор, применяемый к монаде Identity. (Они не всегда реализуются так, как это непосредственно, но должны быть эквивалентными по модулю снизу.) Но не все монады являются трансформаторами (они должны быть универсально левыми или универсально правыми, чтобы преобразовать.) [/]

Подъем и друзья тоже очень полезны, но я считаю, что лучше всего инвертировать ваш процесс.