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: ことはじめ