有一个惰性/严格的Writer版本有什么意义?

为什么Haskell中有两种不同的Writer类型monad? 直观地看,读“严格的作家monad”意味着<>严格,所以日志中没有thunk积累。 但是,从源代码看,情况并非如此:

-- Lazy Writer
instance (Monoid w, Monad m) => Monad (WriterT w m) where
-- ...
m >>= k  = WriterT $ do
    ~(a, w)  <- runWriterT m
    ~(b, w') <- runWriterT (k a)
    return (b, w <> w')

在严格的版本中,模式不是无可辩驳的,即~缺失。 所以上面发生的是mka不被评估,而是以thunk存储。 在严格版本中,评估它们以检查它们是否匹配元组模式,结果被馈送到<> 。 在这两种情况下, >>=都不会被评估,除非实际需要结果值。 所以,我理解它的方式是,无论是懒惰和严格的版本做同样的事情,不同的是他们在定义内的不同位置形实转换>>= :懒产生runWriterT的thunk,严格的生产<>的thunk。

这让我有两个问题:

  • 是上面的权利,还是我误解评价在这里?
  • 我能否完成严格的<>而无需编写自己的包装和实例?

  • 你的第一个观察是正确的,但是这个Thunk创建的区别很重要。

    LazyStrict不是关于日志类型的严格性,而是关于对的严格性。

    这是因为Haskell中的一对有两种可能的方式来更新它。

    bimap f g (a,b) = (f a, g b)
    

    要么

    bimap f g ~(a,b) = (f a, g b)
    

    后者与之相同

    bimap f g p = (f (fst p), g (snd p))
    

    这两者之间的区别在于,如果您在第一种情况下将参数传递给bimap ,则会立即强制该对。

    在后一种情况下,这一对并不是立即强制的,但我反而给你一个(,)回填两个非严格的计算。

    这意味着

    fmap f _|_ = _|_ 
    

    在第一种情况下,但

    fmap f _|_ = (_|_, _|_)
    

    在第二副懒惰的一对情况下!

    在对一对概念的不同解释下,两者都是正确的。 一种是假装一对强迫你是在绝对意义上的对,它没有任何有趣_|_的在自己的权利。 另一方面,该领域的解释是非严格的。 尽可能让所有尽可能多的程序终止,让你进入Lazy版本。

    (,) e是一个完全可以接受的Writer ,所以这就是问题的特征。

    区分的原因在于,重要的是终止许多通过monad获得固定点的外来程序。 只要他们懒惰,你就可以回答关于某些涉及州或作家的循环计划的问题。

    请注意,在这两种情况下,'log'参数都不是严格的。 一旦发生严重错误,你会失去适当的关联性,并在技术上停止成为Monad 。 = /

    因为这不是一个monad,我们不提供它在mtl

    有了这个,我们可以解决你的第二个问题:

    虽然有一些解决方法。 你可以建立一个假的Writer之上State 。 基本上假装你不是一个国家的论点。 和刚刚mappend进入状态,你会tell 。 现在你可以严格执行此操作,因为它不会发生在你背后,作为每一次绑定的一部分。 State只是在行动之间通过未经修改的国家。

    shout :: Monoid s => s -> Strict.StateT s m ()
    shout s' = do
       s <- get
       put $! s <> s'
    

    然而,这意味着你迫使你的整个State monad获得输出,并且Monoid产生Monoid一部分,但是你得到的东西在操作上更接近严格的程序员所期望的。 有趣的是这个工程即使只有Semigroup ,因为只有使用mempty在开始有效的是,当你runState

    链接地址: http://www.djcxy.com/p/42995.html

    上一篇: What is the point of having a lazy/strict version of Writer?

    下一篇: strict vs non