【问题标题】:Writer implemented with Operational Monad does not work lazily用 Operational Monad 实现的 Writer 不能懒惰地工作
【发布时间】:2011-12-26 10:48:42
【问题描述】:

我使用 Operational Monad 方法编写了一个具有 Writer 功能的 monad。然后我注意到它不能懒惰地工作。

在下面的代码中,有一个rogueWriter 执行无限多个语句,每个语句都写入一个字符串。程序不会终止,只是需要无限输出的一些字符。

经过我的分析,我注意到流氓作家实际上非常友好(哈哈),因为当我从runMyWriter rogueWriter 更改为runWriter rogueWriter 时,一切顺利。

问题:

  1. 如何最好地解释这种行为?
  2. 我应该如何更改我的代码以使其正常工作?
  3. 什么 monad 转换器 SomeMonadT
    SomeMonadT Writer w 分别出现同样的问题。 WriterT w SomeMonad (也许是一些例子?)

编辑:我是否有可能在这里尝试反转无限字符串? Sjoerd Visscher 的解决方案与我的一个显着区别是

w `mappend` ws  resp.  ws `mappend` w

代码:

{-# LANGUAGE GADTs, FlexibleContexts, TypeSynonymInstances,
                    FlexibleInstances, MultiParamTypeClasses #-}

module Writer where

import Control.Monad.Identity
import Control.Monad.Operational
import Control.Monad.Writer
import Data.Monoid

data MyWriterI w a where
    Tell :: w -> MyWriterI w ()

type MyWriterT w = ProgramT (MyWriterI w)

type MyWriter w = (MyWriterT w) Identity

runMyWriterT :: (Monad m, Monoid w) => MyWriterT w m a -> m (a, w)
runMyWriterT prog = run prog mempty
  where
    run prog ws = viewT prog >>= flip eval ws
    eval (Return a)       ws = return (a, ws)
    eval (Tell w :>>= is) ws = run (is ()) (ws `mappend` w)

runMyWriter :: (Monoid w) => MyWriter w a -> (a, w)
runMyWriter prog = runIdentity (runMyWriterT prog)

instance (Monad m, Monoid w) => MonadWriter w (MyWriterT w m) where
    tell   = singleton . Tell
    listen = undefined
    pass   = undefined

-- Demonstration of the problem:

rogueWriter :: MonadWriter String m => m ()
rogueWriter = mapM_ (tell . show) [1..]

main = let (_, infiniteOutput) = runMyWriter rogueWriter
       in putStrLn (take 20 infiniteOutput)

【问题讨论】:

  • IIRC,operational 上的 Monad.Reader 文章说你不能用它来做惰性状态单子;也许这是相关的。
  • 看到(tell . show)触发了小学的随机记忆:)
  • @ehird 我不这么认为,因为 Sjoerd 的解决方案运行良好。

标签: haskell monads lazy-evaluation monad-transformers writer-monad


【解决方案1】:

我不知道你的程序失败的确切原因,但我会这样写:

runMyWriterT prog = run prog
  where
    run prog = viewT prog >>= eval
    eval (Return a)       = return (a, mempty)
    eval (Tell w :>>= is) = do
      ~(r, ws) <- run (is ())
      return (r, w `mappend` ws)

【讨论】:

  • 2) 已回答,3) 现在可能已过时:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-23
  • 2011-05-14
  • 1970-01-01
  • 2020-05-04
  • 2022-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多