【发布时间】:2019-05-02 16:41:51
【问题描述】:
我正在使用Control.Monad.Writer.Lazy 编写我的代码,并使用(,) [String] 作为我的作家monad。但是我发现(>>=)和(>>)对monoid算子太严格了?例如,它们会使用以下代码导致无限循环:
type Wrtr a = ([String], a)
writer (x, w) = (w, x)
main :: IO ()
main = do
let one = writer ((), ["goodbye"])
let w = foldr1 (>>) $ repeat one
let (log, _) = w
mapM_ putStrLn . take 5 $ log
这段代码将无限循环,从不打印任何内容,这对我很不利。所以现在我正在使用同一个 monad 的这个幼稚的实现,这似乎很好而且很懒惰:
data Writer w a = Writer w a
instance Functor (Writer w) where
fmap f (Writer w x) = Writer w (f x)
instance Monoid w => Applicative (Writer w) where
pure x = Writer mempty x
(Writer w1 f) <*> (Writer w2 x) = Writer (w1 <> w2) (f x)
instance Monoid w => Monad (Writer w) where
return = pure
(Writer w1 x) >>= f =
let (Writer w2 y) = f x
in Writer (w1 <> w2) y
writer (x, w) = Writer w x
(由于幺半群约束,你必须定义函子和应用实例)
如果您随后使用与上述完全相同的 main 函数运行代码,它将打印五次“再见”并退出。
所以问题是:为什么元组如此严格?或者如果不是严格,那是什么,为什么会存在?
顺便说一句,我正在使用 ghc 8.6.4 以及堆栈 lts-13.19 附带的所有其他内容
【问题讨论】:
-
我不明白“我正在使用 Control.Monad.Writer.Lazy 编写代码,使用 (,) [String] 作为我的 writer monad。”如果您使用的是
(,) [String]monad,那么您没有使用Control.Monad.Writer.Lazy。我猜basemonad(,) [String]与Control.Monad.Writer.Strict.Writer [String]同构,它应该在你的代码上循环(一旦适应)。 -
我该死的我读错了。我以为这个模块只导出了实例和方法,没有注意到
Writer本身。是时候测试一下了。
标签: haskell monads lazy-evaluation