gpt4 book ai didi

haskell,IO Monoid 关联性被打破了吗?

转载 作者:行者123 更新时间:2023-12-05 08:14:28 27 4
gpt4 key购买 nike

在 haskell IO 类型中有 Monoid 的实例:

instance Monoid a => Monoid (IO a) where
mempty = pure empty

如果我有三个 Action 共享一些状态,并通过副作用改变彼此的行为,从 IO 类型的角度来看,这可能会导致违反关联律:

a1:: IO String
a2:: IO String
a3:: IO String

(a1 mappend a2) mappend a3/= a1 mappend (a2 mappend a3)

例如,如果 a1、a2、a3 以字符串形式请求当前时间,或者 IO 包含一些计算请求编号的 DB。这意味着它可以:

(a1 `mappend` a2) `mappend` a3  == "1"++"2"++"3"
a1 `mappend` (a2 `mappend` a3) == "3"++"1"++"2"

编辑:

我想我不应该给出一个数据库的例子,它很困惑,更优选的例子:

a1 = show <$> getUnixTime 
a2 = show <$> getUnixTime
a3 = show <$> getUnixTime

l = (a1 `mappend` a2) `mappend` a3
r = a1 `mappend` (a2 `mappend` a3)
liftA2 (==) l r
**False**

那么,如果 IO 类型可以打破结合律,为什么它是幺半群呢?还是我遗漏了什么?

最佳答案

a1 `mappend` (a2 `mappend` a3)未按 a2 顺序运行, a3a1 .例如,与 Python 这样的命令式语言相比,Haskell 中的 IO a不是计算的某些结果,它是产生a 值的配方 .你实际上可以看到 IO更像是 Python 中的延续,您传递一个最终可以调用它的函数,但您不直接调用它。

mappend函数实现为 liftA2 (<>)对于 Semigroup a => Semigroup (IO a)例如,正如我们在 source code 中看到的那样:

instance Semigroup a => Semigroup (IO a) where
(<>) = liftA2 (<>)

因此这意味着 mappend实现为:

mappendIO :: Semigroup a => IO a -> IO a -> IO a
mappendIO f g = do
x <- <b>f</b>
y <- <b>g</b>
pure (x <> y)

所以它运行f之前g .

如果我们现在看(a1 `mappend` a2) `mappend` a3 ,我们看到:

(a1 `mappend` a2) `mappend` a3 = do
x <- do
x1 <- a1
x2 <- a2
pure (x1 <> x2)
y <- a3
pure (x <> y)

相当于:

(a1 `mappend` a2) `mappend` a3 = do
x1 <- a1
x2 <- a2
x3 <- a3
pure ((x1 <> x2) <> x3)

如果我们再看看 a1 `mappend` (a2 `mappend` a3)那么这相当于:

a1 `mappend` (a2 `mappend` a3) = do
x <- a1
y <- do
y1 <- a2
y2 <- a2
pure (y1 <> y2)
pure (x <> y)

相当于:

a1 `mappend` (a2 `mappend` a3) = do
x1 <- a1
x2 <- a2
x3 <- a2
pure (x1 <> (x2 <> x3))

x1 <> (x2 <> x3)相当于(x1 <> x2) <> x3 ,这将因此在两个项目中返回相同的结果。

至于你的测试:

l = (a1 `mappend` a2) `mappend` a3
r = a1 `mappend` (a2 `mappend` a3)
liftA2 (==) l r
False

请注意 liftA2 (==) again 将定义一个序列,所以这意味着你的liftA2 (==) l r定义为:

liftA2 (==) l r = do
x1 <- a1
x2 <- a2
x3 <- a3
y1 <- a1
y2 <- a2
y3 <- a3
pure ((x1 <> x2) <> x3) == (y1 <> (y2 <> y3))

您因此运行 r 之后 l .

如果您使用 State monad,你可以更清楚地知道会发生什么,并验证规则是否被应用。您需要重置 l 之间的状态和 r然而。

关于haskell,IO Monoid 关联性被打破了吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64948364/

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