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

标签 haskell monads monad-transformers 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')

在严格版本中,模式并非无可辩驳,即 ~缺失。所以上面发生的是mk a不评估,但存储为 thunk。在严格的版本中,它们被评估以检查它们是否匹配元组模式,结果被馈送到<>。 .在这两种情况下,>>=直到某些东西真正需要结果值时才被评估。
所以我的理解是惰性和严格版本都做同样的事情,除了它们在 >>= 的定义中的不同位置有 thunk : 懒惰产生 runWriterT thunks,严格产生 <>重击。

这给我留下了两个问题:
  • 以上是对的,还是我误解了这里的评价?
  • 我能做到严格吗<>不编写我自己的包装器和实例?
  • 最佳答案

    您的第一个观察结果是正确的,但是创建的 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))
    

    这两者之间的区别在于,当您将 args 传递给 bimap在第一种情况下,该对立即被强制。

    在后一种情况下,这对不会立即被强制,而是我给你一个 (,)后面充满了两个非严格的计算。

    这意味着
    fmap f _|_ = _|_ 
    

    在第一种情况下,但是
    fmap f _|_ = (_|_, _|_)
    

    在第二个懒惰的情况下!

    在对一对概念的不同解释下,两者都是正确的。假装一对是绝对意义上的一对,这是强制你的,它没有任何有趣的_|_是在它自己的权利。另一方面,将域解释为非严格的。尽可能让尽可能多的程序终止,从而将您引导至 Lazy版本。
    (,) e是完全可以接受的Writer ,所以这表征了问题。

    区分的原因是它对于终止许多通过 monad 采用固定点的奇异程序很重要。您可以回答有关涉及 State 或作家的某些循环计划的问题,只要它们是懒惰的。

    请注意,在这两种情况下,'log' 参数都不是严格的。一旦你受到严格的约束,你就会失去适当的关联性,并且在技术上不再是 Monad . =/

    因为这不是一个 monad,所以我们不在 mtl 中提供它。 !

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

    不过有一些解决方法。你可以构造一个假的WriterState 之上.基本上假装你没有收到状态论据。并像您一样将其映射到状态 tell .现在您可以严格执行此操作,因为它不会作为每次绑定(bind)的一部分在您背后发生。 State只是通过 Action 之间未修改的状态。
    shout :: Monoid s => s -> Strict.StateT s m ()
    shout s' = do
       s <- get
       put $! s <> s'
    

    但是,这确实意味着您强制使用整个 State monad 来获取输出,并且不能产生 Monoid 的一部分懒惰,但你得到的东西在操作上更接近严格的程序员所期望的。有趣的是,即使只使用 Semigroup 也可以使用。 , 因为 mempty 的唯一用途当你 runState 开始时有效.

    关于haskell - 拥有一个惰性/严格版本的 Writer 有什么意义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14644830/

    相关文章:

    haskell - 操作 monad 堆栈

    monads - 为什么要为 monad 定义单位自然变换——这不是 monad 是内仿函数的定义所暗示的吗?

    haskell - 如何在计算随机值的 haskell 程序中构造 monad?

    haskell - 'State' 的数据构造函数在哪里?

    opengl - 如何获得光泽而不关闭ghci?

    f# - F# 的 monad 实现在可用关键字数量方面是独一无二的吗?

    haskell - 函数末尾的下划线在 Haskell 中是什么意思?

    scala - 当嵌套很深时如何处理所有单子(monad)结构?

    Haskell 从 IO 域获取值

    haskell - 是否可以实现 `(Applicative m) => Applicative (StateT s m)` ?