haskell - 为什么 ParsecT 没有 MonadWriter 实例?

标签 haskell monads monad-transformers parsec

我今天早些时候正在写一些 Haskell。想出了一些类似的东西

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype Foo a = Foo { ParsecT String () (Writer DefinitelyAMonoid) a }
    deriving (Functor, Applicative, Monad, MonadWriter DefinitelyAMonoid)

这没有编译。 “没有由数据类型声明的'派生'子句引起的 (MonadWriterdefiniteAMonoid (ParsecT String () (WriterdefiniteAMonoid))) 的实例”,GHC 告诉我。所以我决定看看其他一些 MTL 类是否可以工作,他们做到了。 ReaderMonadReader,以及 WriterMonadWriter。所以我被一个 Discord 用户定向到 Hackage ,问题很明显:

MonadState  s m => MonadState  s (ParsecT s' u m)
MonadReader r m => MonadReader r (ParsecT s  u m)
MonadError  e m => MonadError  e (ParsecT s  u m)

没有 MonadWriter 实例可以通过 ParsecT 转换器!在我看来,全世界都只是一个疏忽,而在在 Github 上打开一个问题之前,我几乎没有意识到这可能是故意的。所以我看了一下Megaparsec :

(Stream s, MonadState st m) => MonadState st (ParsecT e s m)
(Stream s, MonadReader r m) => MonadReader r (ParsecT e s m)
(Stream s, MonadError e' m) => MonadError e' (ParsecT e s m)

同样,没有 MonadWriter

为什么 Parsec 和 Megaparsec 都不为 ParsecT 提供 MonadWriter 实例?像这样的解析器 monad 是否有什么特别之处使它们无法与作家相处融洽?有没有类似 this 的东西继续?

最佳答案

Parsec 是一个回溯单子(monad)。虽然您提出的 MonadWriter 实例并非不可能,但将 Writer 置于回溯 monad 之下是一件奇怪的事情。这是因为 monad 堆栈的内层提供了外层构建的“基础”效果——也就是说,无论 ParsecT u (Writer w) 做什么,它只能这样做 告诉而言。因此,如果它 tell 是分支中的一个值,该值后来被回溯出,则不可能“取消”该值,因此 Writer 的结果将是更像是解析算法的痕迹,而不是 Parsec 呈现的数据流抽象的痕迹。这不是没用,但很奇怪,如果 WriterT 在外面,Parsec 在里面,你会有更自然的语义。

同样的论点适用于State。 Parsec 公开了它自己的用户状态功能(u 参数)和一个继承底层 monad 状态功能的 MonadState 实例。后者带有与 MonadWriter 相同的警告——状态性遵循算法的轨迹,而不是数据流。我不知道为什么包含了这个实例,而 Writer 实例却没有;它们都以同样的方式棘手。

-- I'm presuming the user might want a separate, non-backtracking
-- state aside from the Parsec user state.
instance (MonadState s m) => MonadState s (ParsecT s' u m) where
    get = lift get
    put = lift . put

另一方面,Parsec 的用户状态遵循数据流,而不是计算,它与将 StateT 放在外部具有相同的效果。 Parsec 提供自己的状态工具而不是仅仅要求我们使用转换器似乎总是很奇怪——但是,现在考虑一下,我怀疑这只是为了避免不得不将 lift如果你碰巧使用了 state。

总之,他们可以提供您要求的 MonadWriter 实例,但我认为有充分的理由不这样做 - 以阻止犯我认为您可能正在犯的错误。

关于haskell - 为什么 ParsecT 没有 MonadWriter 实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64530494/

相关文章:

haskell - (<*>) 中的 * 有特殊含义吗?

haskell - 在 Haskell 中执行一系列操作时的异常处理

haskell - 图层和可扩展效果之间有什么区别?

haskell - 使用 Reader 扩展 ServerPartT Monad

haskell - MaybeT 的直觉

sorting - 如何使用列表理解在 Haskell 中检查列表是否已排序?

haskell - Haskell中的运算符优先级

Haskell 中的字符串解析

haskell - 重构 where 子句

haskell - 什么是单子(monad)类别的仿函数?