2010-11-09 4 views
15

Допустим, у меня есть функцияКомбинирование StateT и государственные монады

f :: State [Int] Int 

и функции:

g :: StateT [Int] IO Int 

Я хочу использовать f в g и передавать состояние между ними. Есть ли библиотечная функция для
StateT (return . runState f)? Или вообще, учитывая монадный трансформатор с соответствующей монадой, есть ли для него библиотечная функция?

+0

Я считаю, что редактировать TomMD является некорректным. Я считаю, что исходный 'g :: StateT [Int] IO Int' должен стоять. – glguy

+0

Мне понравились другие изменения, исправлены скобки ... – HaskellElephant

+1

Этот вопрос кажется тем, что я ищу, но ответы намного сложнее, чем http://stackoverflow.com/questions/17325485/combining-statet- io-with-state, который получил работу для меня. – crockeea

ответ

5

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

fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 a) -> t m1 a -> t m2 a 

В принципе более высокого уровня fmap. На самом деле, это, вероятно, сделать еще более смысл совместить его с картой над окончательным параметром, а также:

fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 b) -> t m1 a -> t m2 b 

Очевидно, что это не собирается быть возможно во всех случаях, хотя, когда «источник» монады Identity, это, вероятно, будет проще, но я могу представить, как определить класс другого типа для мест, в которых он работает. Я не думаю, что в типичных библиотеках трансформаторов монады есть что-то подобное; Однако, некоторый просмотр на hackage получается что-то очень похожее in the Monatron package:

class MonadT t => FMonadT t where 
    tmap' :: FunctorD m -> FunctorD n -> (a -> b) 
      -> (forall x. m x -> n x) -> t m a -> t n b 

tmap :: (FMonadT t, Functor m, Functor n) => (forall b. m b -> n b) 
     -> t m a -> t n a 
tmap = tmap' functor functor id 

В подписи для tmap', то FunctorD типов в основном одноранговые реализации fmap вместо использования Functor экземпляров непосредственно.

Кроме того, в течение двух Functor-подобных конструкторов типа F и G, функция с типом как (forall a. F a -> G a) описывает a natural transformation от F до G. Там вполне возможно, другая реализация карты трансформатора, который вы хотите где-то в category-extras пакете, но я «Не знаю, что такое теоретическая версия трансформатора монады, поэтому я не знаю, как это можно назвать.

Поскольку tmap требует только Functor экземпляра (который любой Monad должен иметь) и естественное преобразование, и любая Monad имеет естественное преобразование из Identity монады, предоставленной return, функция, которую вы хотите, может быть записана в общей для любого экземпляра FMonadT as tmap (return . runIdentity) - Исходная «основная» монада определяется как синоним трансформатора, примененный к Identity, во всяком случае, как правило, с библиотеками трансформаторов.

Возвращаясь к вашему конкретному примеру, обратите внимание, что у Monatron действительно есть экземпляр FMonadT для StateT.

+0

Я не смотрел пакет Monatron. Мне придется присмотреться к этому, чтобы судить об этом. Мне нравится ваша идея определить класс типа, когда он работает, может ли кто-нибудь подтвердить или подтвердить, что Monatron делает это? – HaskellElephant

4

Такая функция не может быть определена для всех монадных трансформаторов. Например, монада Cont r не может быть поднята до ContT r IO, потому что это потребовало бы продолжения в монаде IO (a -> IO r) в чистое продолжение (a -> r).

+0

Не думал об этом. Как вы сказали, это невозможно для каждого монадрансформатора. Так что для этого потребуется особый вид связи между трансформатором и соответствующей монадой ... – HaskellElephant

+0

Не изменилось бы превращение в другую сторону? Поскольку тип 'r' в продолжении обычно является полиморфным, вы можете просто написать '(ContT. RunCont) :: Cont (m r) a -> ContT r m a'. –

+0

@camccann Я собирался для обобщенного класса преобразований (Monad m => m a -> (TransformerOf m) m 'a) (немного злоупотребляя нотацией). Если вы попытаетесь написать экземпляр для (Cont r a -> ContT r m a), вы застрянете в той точке, которую я описал. – Heatsink

4

То, что вы просите за это отображение (известный как монады морфизма) от монады StateT m к StateT n. Я буду использовать библиотеку mmorph, которая предоставляет очень хороший набор инструментов для работы с морфологиями монады.

Для выполнения State -> StateT m преобразования вы ищете, мы начнем с определением морфизма обобщить Identity монады, внедренную в State,

generalize :: Monad m => Identity a -> m a 
generalize = return . runIdentity 

Далее мы хотим поднять этот морфизм действовать на внутренняя монада вашего StateT. То есть, мы хотим, чтобы функция, которая давала отображение от одной монады к другой (например, наш морфизм generalize), даст нам функцию, действующую на базовую монаду монадного трансформатора, например. t Identity a -> t m a. Вы найдете это напоминает hoist функцию mmorph «s MFunctor класса,

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

Ввод куски вместе,

myAction :: State s Int 
myAction = return 2 

myAction' :: Monad m => StateT s m Int 
myAction' = hoist generalize myAction 
Смежные вопросы