Трансформатор Monadity Monadity

Я пытаюсь разделить монаду IResult от attoparsec на несколько частей. Здесь IResult

data IResult t r = Fail t [String] String
                 | Partial (t -> IResult t r)
                 | Done t r

Похоже, что это должно быть сочетание эффектов, "пристрастности" и неудачи. Если отказ представлен как просто Either ([String], String), то пристрастность может быть

data Partiality t a = Now a | Later (t -> Partiality t a)

instance Monad (Partiality t) where
  return = pure
  (Now a) >>= f = f a
  (Later go) >>= f = Later $ \t -> go t >>= f

class MonadPartial t m where
  feed  :: t -> m a -> m a
  final :: m a -> Bool

instance MonadPartial t (Partiality t) where
  feed _ (Now a) = Now a
  feed t (Later go) = go t
  final (Now _) = True
  final (Later _) = False

(который получает тезку от статью Даниэльссона, когда вы используете Partiality ())

Я мог бы использовать Partiality в качестве базовой монады, но есть ли монадный трансформатор PartialityT?

Ответ 1

Конечно! Ваша монада Partiality - свободная монада:

import Control.Monad.Free  -- from the `free` package

type Partiality t = Free ((->) t)

... и соответствующий PartialityT является свободным монадным трансформатором:

import Control.Monad.Trans.Free  -- also from the `free` package

type PartialityT t = FreeT ((->) t)

Здесь приведен пример программы, показывающей, как вы ее используете:

import Control.Monad
import Control.Monad.Trans.Class
import Control.Monad.Trans.Free

type PartialityT t = FreeT ((->) t)

await :: (Monad m) => PartialityT t m t
await = liftF id

printer :: (Show a) => PartialityT a IO r
printer = forever $ do
    a <- await
    lift $ print a

runPartialityT :: (Monad m) => [a] -> PartialityT a m r -> m ()
runPartialityT as p = case as of
    []   -> return ()
    a:as -> do
        x <- runFreeT p
        case x of
            Pure _ -> return ()
            Free k -> runPartialityT as (k a)

Мы создаем бесплатный трансформатор монады с помощью команды await для запроса новых значений и lift для вызова действий в базовой монаде. Мы получаем экземпляры Monad и MonadTrans для PartialityT бесплатно, потому что свободный монадный трансформатор автоматически является монадным и монадным трансформатором для любого заданного функтора.

Мы запускаем вышеуказанную программу следующим образом:

>>> runPartialityT [1..] printer
1
2
3
...

Я рекомендую вам прочитать этот пост, который я написал о свободных монадных трансформаторах. Тем не менее, новым официальным домом бесплатного монада-трансформатора является пакет free.

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