Semigroup 和 Monoid 实例中的约束差异
Difference of constraints in Semigroup and Monoid instances
为什么 Monoid 实例需要 (Ord a, Ord b) 约束而 Semigroup 实例不需要?
这取决于 Category.Constrained class 还是使用 GADT 来定义数据类型?
{-# LANGUAGE GADTs, TypeFamilies, ConstraintKinds, StandaloneDeriving #-}
module Question3 where
import Control.Category.Constrained as CC
import Data.Set as S
import Data.Map as M
data RelationMS a b where
IdRMS :: RelationMS a a
RMS :: (Ord a, Ord b) => Map a (Set b) -> RelationMS a b
deriving instance (Show a, Show b) => Show (RelationMS a b)
RMS mp2 `compRMS` RMS mp1
| M.null mp2 || M.null mp1 = RMS M.empty
| otherwise = RMS $ M.foldrWithKey
(\k s acc -> M.insert k (S.foldr (\x acc2 -> case M.lookup x mp2 of
Nothing -> acc2
Just s2 -> S.union s2 acc2
) S.empty s
) acc
) M.empty mp1
instance Category RelationMS where
type Object RelationMS o = Ord o
id = IdRMS
(.) = compRMS
instance Semigroup (RelationMS a b) where
RMS r1 <> RMS r2 = RMS $ M.foldrWithKey (\k s acc -> M.insertWith S.union k s acc) r1 r2
instance (Ord a, Ord b) => Monoid (RelationMS a b) where
mempty = RMS $ M.empty
mappend = (<>)
Why Monoid instance need (Ord a, Ord b) constraints while Semigroup instance doesn't?
尝试移除约束并让 GHC 告诉您原因。
ac.hs:33:14: error:
• No instance for (Ord a) arising from a use of ‘RMS’
Possible fix:
add (Ord a) to the context of the instance declaration
• In the expression: RMS $ M.empty
In an equation for ‘mempty’: mempty = RMS $ M.empty
In the instance declaration for ‘Monoid (RelationMS a b)’
|
33 | mempty = RMS $ M.empty
|
所以 RMS
需要 Ord a
?你说:
RMS :: (Ord a, Ord b) => Map a (Set b) -> RelationMS a b
所以,是的。
这肯定与类别实例无关。
Semigroup
实例至少在概念上也需要 Ord
,但是您已经将其打包到 GADT 中(Id
情况除外,它不是需要,因为它很简单),因此无需在实例头中提及约束。
然而,对于 mempty
,您 没有 手头的 RelationMS
值,您可以从中读出 (Ord a, Ord b)
约束.恰恰相反:您需要提供这些约束,因为您现在正试图结束这样一个 GADT!这就是为什么 Monoid
实例的头部需要约束,而 Semigroup
实例不需要。
为什么 Monoid 实例需要 (Ord a, Ord b) 约束而 Semigroup 实例不需要?
这取决于 Category.Constrained class 还是使用 GADT 来定义数据类型?
{-# LANGUAGE GADTs, TypeFamilies, ConstraintKinds, StandaloneDeriving #-}
module Question3 where
import Control.Category.Constrained as CC
import Data.Set as S
import Data.Map as M
data RelationMS a b where
IdRMS :: RelationMS a a
RMS :: (Ord a, Ord b) => Map a (Set b) -> RelationMS a b
deriving instance (Show a, Show b) => Show (RelationMS a b)
RMS mp2 `compRMS` RMS mp1
| M.null mp2 || M.null mp1 = RMS M.empty
| otherwise = RMS $ M.foldrWithKey
(\k s acc -> M.insert k (S.foldr (\x acc2 -> case M.lookup x mp2 of
Nothing -> acc2
Just s2 -> S.union s2 acc2
) S.empty s
) acc
) M.empty mp1
instance Category RelationMS where
type Object RelationMS o = Ord o
id = IdRMS
(.) = compRMS
instance Semigroup (RelationMS a b) where
RMS r1 <> RMS r2 = RMS $ M.foldrWithKey (\k s acc -> M.insertWith S.union k s acc) r1 r2
instance (Ord a, Ord b) => Monoid (RelationMS a b) where
mempty = RMS $ M.empty
mappend = (<>)
Why Monoid instance need (Ord a, Ord b) constraints while Semigroup instance doesn't?
尝试移除约束并让 GHC 告诉您原因。
ac.hs:33:14: error:
• No instance for (Ord a) arising from a use of ‘RMS’
Possible fix:
add (Ord a) to the context of the instance declaration
• In the expression: RMS $ M.empty
In an equation for ‘mempty’: mempty = RMS $ M.empty
In the instance declaration for ‘Monoid (RelationMS a b)’
|
33 | mempty = RMS $ M.empty
|
所以 RMS
需要 Ord a
?你说:
RMS :: (Ord a, Ord b) => Map a (Set b) -> RelationMS a b
所以,是的。
这肯定与类别实例无关。
Semigroup
实例至少在概念上也需要 Ord
,但是您已经将其打包到 GADT 中(Id
情况除外,它不是需要,因为它很简单),因此无需在实例头中提及约束。
然而,对于 mempty
,您 没有 手头的 RelationMS
值,您可以从中读出 (Ord a, Ord b)
约束.恰恰相反:您需要提供这些约束,因为您现在正试图结束这样一个 GADT!这就是为什么 Monoid
实例的头部需要约束,而 Semigroup
实例不需要。