首页 > 解决方案 > Semigroup 和 Monoid 实例中约束的差异

问题描述

为什么 Monoid 实例需要 (Ord a, Ord b) 约束,而 Semigroup 实例不需要?

这是否取决于 Category.Constrained 类或使用 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 = (<>)

标签: haskellcategory-abstractions

解决方案


这当然与类别实例无关。

Semigroup至少在概念上,该实例确实也需要Ord,但是您已经将其打包在 GADT 中(除非在这种Id情况下,因为它很简单而不需要它),因此无需在实例头中提及约束。

mempty但是,您手头没有可以RelationMS(Ord a, Ord b)约束的值。恰恰相反:您需要提供这些约束,因为您现在正试图结束这样的 GADT!这就是为什么Monoid实例需要在其头部约束,而实例Semigroup不需要。


推荐阅读