查看此IO
代码:
Prelude> let e = return () :: IO ()
Prelude> e `mappend` e
Prelude> let y = e `mappend` e
Prelude> :t y
y :: IO ()
编辑显然,据我所知,IO
有Monoid
个实例。
但是,为了遵守Monoid第三定律,下列评价不应该true
吗?
Prelude> e `mappend` (e `mappend` e) == (e `mappend` e) `mappend` e
<interactive>:14:1: error:
* No instance for (Eq (IO ())) arising from a use of `=='
* In the expression:
e `mappend` (e `mappend` e) == (e `mappend` e) `mappend` e
In an equation for `it':
it = e `mappend` (e `mappend` e) == (e `mappend` e) `mappend` e
答案 0 :(得分:11)
The third monoid law声明e <> (e <> e) = (e <> e) <> e
(使用mappend
更容易输入的中缀运算符),不 e <> (e <> e) == (e <> e) <> e
(注意=
与==
)。
它表达了一个等价 - 实际上,表达mappend
应该是关联的 - 不要求所有Monoid
s也必须是Eq
类型类的实例,其中{{1}来自。
另一种说法是:它表达了关于==
函数行为的高级概念,没有呈现有效的Haskell代码,应该特别评估任何东西。
某些类型mappend
s - 例如Monoid
- 也碰巧有[()]
个实例。但是有些人(比如这里的Eq
实例)没有,这没关系。
旁注:给
IO ()
一个IO
实例是没有意义的,因为几乎不可能确定某个Eq
是否等同于另一个IO ()
IO ()
}。putStrLn "3"
“等于”print 3
吗?它们都具有相同的可观察效果,但运行时如何确定在一般情况下?并且你不能说“如果它们产生相同的值,它们就是等价的”,因为==
的返回类型必须是IO Bool
,而这不是{Eq
的正确签名。 1}}。所以我们只是不给IO
一个Eq
实例,这没关系 - 我无法想出一个合理的例子来说明这样的实例何时有用。
另请注意,“IO
”没有Monoid
个实例(无论如何都是错误的类型)。您正在使用的mappend
来自Monoid a => Monoid (IO a)
的实例 - 也就是说,IO配方可以生成本身为Monoid
的类型。 IO
的{{1}}个实例只是“捎带”在基础Monoid
实例上。