【问题标题】:Does Backwards admit a Monad instance?Backwards 是否承认 Monad 实例?
【发布时间】:2015-12-15 20:25:44
【问题描述】:

我刚刚在 haskell-cafe 上问过这个问题,但我想我也不妨在这里问一下。 Backwards m 的以下 Monad 实例是否有效?

{-# Language RecursiveDo #-}

import Control.Applicative.Backwards
import Control.Monad.Fix

instance MonadFix m => Monad (Backwards m) where
  m >>= f = Backwards $
    do
      fin <- forwards (f int)
      int <- forwards m
      pure fin

如果是这样,我也可以添加这个吗?

instance MonadFix m => MonadFix (Backwards m) where
  mfix f = Backwards $ mfix (forwards . f)

【问题讨论】:

    标签: haskell monads


    【解决方案1】:

    不,无效;单子定律充其量以某种近似的方式成立。正如Petr Pudlák's answer 所示,当f 的参数很严格时,Backwards m &gt;&gt;= f 的行为并不是很好。

    根据单子定律,

    pure () >>= (\() -> m)   =   m
    

    但是如果我没记错的话,这个例子,

    pure () >>= (\() -> m) = Backwards $ do
      fin <- forwards (int `seq` m)
      int <- pure ()
      pure fin
      = Backwards $ fmap fst $ mfix $ \ ~(_, int) -> do
         fin <- forwards (int `seq` m)
         pure (fin, ())
    

    如果底层 monad 是“严格的”(即其 &gt;&gt;= 在其左操作数中是严格的),这将发散。

    【讨论】:

      【解决方案2】:

      为此f 需要是惰性的,也就是说,效果不能依赖于参数。 docs

      mfix f 只执行一次操作f,最终输出作为输入反馈。因此f 不应该是严格的,因为那样mfix f 就会发散。

      如果 f 在你的情况下 m &gt;&gt;= f 将是严格的,那么传递给 mfix 的块也是如此。

      让我们考虑一个实际示例,其中mreadLine &gt;&gt;= putStrLn。颠倒顺序意味着“打印数据,然后读取它”。除非&gt;&gt;= 后面的函数的效果不依赖于输入,否则这是发散的。

      【讨论】:

      • 是的,我知道这个限制,它极大地限制了实例的实用性。我还不清楚这个限制是否会影响它的有效性
      • 好的,我想我现在明白这是如何破坏事情的了。我发布了一个我怀疑可以证明这一点的答案。
      • 我听说 GHC 8.0 将支持关于IO 的时间旅行。
      猜你喜欢
      • 2014-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-18
      • 1970-01-01
      • 1970-01-01
      • 2021-03-09
      • 1970-01-01
      相关资源
      最近更新 更多