gpt4 book ai didi

Haskell 元组单子(monad)太严格了?

转载 作者:行者123 更新时间:2023-12-04 17:29:40 24 4
gpt4 key购买 nike

我正在用 Control.Monad.Writer.Lazy 编写我的代码使用 (,) [String]作为我的作家单子(monad)。但我发现(>>=)(>>)对幺半群算子是否过于严格?它们使用此代码导致无限循环,例如:

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 附带的所有其他内容

最佳答案

那是因为你的 Writer违反单子(monad)定律。看看这个法律:

-- forall (f :: a -> Writer m b) (x :: a).
return x >>= f = f x
-- basically f (id x) = f x, which we should agree is pretty important!

但是,唉,它不成立! let f = undefined ! (或 f = const undefined ;如果您不使用 seq,它们将无法区分)
  return x >>= undefined
= Writer mempty x >>= undefined
= let (Writer m y) = undefined
in Writer (mempty <> m) y
= Writer (mempty <> undefined) undefined

然而,根据法律,
  return x >>= undefined
= undefined x
= undefined

这些不相等,因此您的懒惰 Monad实例是非法的(是的,我相信 mtl 中的实例也是如此)。但是, Fast and Loose Reasoning is Morally Correct ,所以我们一般只接受它。这个想法是一个懒惰的 Writer monad 通常遵循它应该遵循的法则,只要你保持无限或触底值,但它在那些边缘情况下会崩溃。相比之下,严格执行是完全合法的,这就是它在 base中的原因。 .但是,正如您所发现的,当懒惰时 Writer s 违反了法律,他们以一种有用的方式这样做,所以我们将惰性实现放在 mtl .

这是 demo of this behavior .请注意,惰性版本会生成 Writer "在炸毁之前的输出中,而严格的版本和法律给出的规范都没有这样做。

关于Haskell 元组单子(monad)太严格了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55956853/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com