Первое, что нужно заметить, это то, что изменение inj
превращает Free
в нечто почти монадное преобразование.
Я буду использовать Control.Monad.Free из моей бесплатной посылки на хакер, чтобы не повторять здесь все.Это означает, что Roll
становится Free
, а Return
вместо этого именуется Pure
в приведенном ниже коде относительно версии в вики.
import Control.Monad
import Control.Monad.Free -- from 'free'
instance MonadTrans Free where
lift = Free . liftM Pure
Однако вы не можете пойти в другом направлении для произвольного Functor
.Однако, если у вас есть экземпляр Monad
на m
, вы можете отменить подъем, сгладив Free m
вниз до одного слоя базовой монады m
!
retract :: Monad f => Free f a -> f a
retract (Pure a) = return a
retract (Free as) = as >>= retract
Имявыбран, потому что это ретракция из lift
.Так называется, потому что
retract . lift = id
выполняется, как показано
retract (lift as) = -- by definition of lift
retract (Free (liftM Pure as)) = -- by definition of retract
liftM Pure as >>= retract = -- by definition of liftM
as >>= \a -> return (Pure a) >>= retract = -- first monad law
as >>= \a -> retract (Pure a) -- by definition of retract
as >>= \a -> return a = -- eta reduction
as >>= return -- second monad law
as
, поэтому функция retract
отменяет работу lift
.
Поскольку fmap
= liftM
, это верно и для inj
.
Обратите внимание, что lift . retract
- это , а не id
.Просто не хватает места, чтобы поместить все в промежуточный тип - использование монады разбивает все плоско - но lift . retract . lift . retract = lift . retract
держится, потому что lift . retract . lift . retract = lift . id . retract = lift . retract
, поэтому lift . retract
идемпотентно.
проблема с этим «лифтом» заключается в том, что «лифт» не является гомоморфизмом монады, а является лишь мономомизмом монады «до отвода», так что это возлагает бремя сохранения законов преобразователя монад на пользователя поднятых вычислений, поэтомуимеет смысл сохранить inj как отдельное имя функции.
Сейчас я собираюсь добавить retract
в бесплатный пакет прямо сейчас.Мне это нужно было недавно для статьи, которую я пишу в любом случае.