Type class で可換半郡を次のように書いていた.
class CommutativeMonoid a where
oplus :: a -> a -> a, -- commutative, associative
identity::a -- the identity of oplus
data Bag a = Bag [a] deriving (Show,Ord,Read)
instance CommutativeMonoid (Bag a) where
oplus (Bag a) (Bag b) = Bag (a ++ b)
identity = Bag []
んで,type class だと不都合が生じたのでレコードで演算をまとめて持ち運ぶようにしたのだけど,定義部分に限っては RecordWildCards を使うとほとんど同じように書ける.演算の集合を定義するという点では type class でもレコードでも手間は大して変わらないっぽいねと. 楽だし簡潔でいい.
data CommutativeMonoid a = CommutativeMonoid {
oplus :: a -> a -> a, -- commutative, associative
identity::a -- the identity of oplus
}
data Bag a = Bag [a] deriving (Show,Ord,Read)
bagMonoid = CommutativeMonoid { .. } where
oplus (Bag a) (Bag b) = Bag (a ++ b)
identity = Bag []
インスタンス宣言に同じクラスの別のインスタンスを使う,例えば
instance (CommutativeMonoid a, Ord c) => CommutativeMonoid (Map c a) where oplus x y = unionWith oplus x y identity = empty
とかも
mapMonoid m = CommutativeMonoid { .. } where
oplus x y = let CommutativeMonoid {..} = m in unionWith oplus x y
identity = empty
と書けばほとんど同じ雰囲気かね.let を内側で使ってあげるのが大事.下のようにやると定義の本体の oplus が新しく定義される oplus になっちゃうのでエラーを食らう.
mapMonoid (CommutativeMonoid {..}) = CommutativeMonoid { .. } where
oplus x y = unionWith oplus x y
identity = empty
- Newer: ことはじめ