我正在试图解构 IResult
monad来自 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
作为基地monad,但是有一个 PartialityT
monad变压器?
肯定有!你的 Partiality
monad是一个免费的monad:
import Control.Monad.Free -- from the `free` package
type Partiality t = Free ((->) t)
......和相应的 PartialityT
是一个免费的monad变换器:
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)
我们用这个构建了免费的monad变换器 await
命令请求新值和 lift
调用基monad中的操作。我们得到了 Monad
和 MonadTrans
实例 PartialityT
免费,因为免费monad变换器自动为任何给定仿函数的monad和monad变换器。
我们像这样运行上面的程序:
>>> runPartialityT [1..] printer
1
2
3
...
我建议你看看 这篇文章我写的关于免费monad变形金刚。然而,免费monad变压器的新官方住宅是 free
包。
此外,如果您正在寻找一个有效的增量解析器,我即将发布它作为 pipes-parse
几天内打包。你可以检查一下 目前的草案在这里。