Reputation: 573
When working with a Bifunctor
, we gain access to the first
and second
"map" functions. So basically it is a Functor
that allows us to fmap
in two different ways.
Is there something like this for Monoid
? Some concept that allows us to append in two different ways?
For example, imagine an opaque Matrix
type. It is not a list of lists or a vector of vectors, we have no clue how it is structured inside, but we know that we can append rows and columns to it.
Would there be some type class that allowed to do this?
class X a where
firstAppend :: a -> a -> a
secondAppend :: a -> a -> a
instance X Matrix where
firstAppend = appendRow
secondAppend = appendColumn
Upvotes: 3
Views: 146
Reputation: 12123
I guess you could do something like this with indexed Monoids:
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
module IndexedMonoids where
class MonoidIx (m :: k -> *) where
type Null m :: k
type Mult m (i :: k) (j :: k) :: k
nullIx :: m (Null m)
multIx :: m i -> m j -> m (Mult m i j)
class MonoidIx2 (m :: k -> l -> *) where
type Null1 m :: k
type Null2 m :: l
type Mult1 m (i :: k) (j :: k) :: k
type Mult2 m (p :: l) (q :: l) :: l
null1Ix :: m (Null1 m) p
null2Ix :: m i (Null2 m)
mult1Ix :: m i p -> m j p -> m (Mult1 m i j) p
mult2Ix :: m i p -> m i q -> m i (Mult2 m p q)
You'd expect a bunch of laws (identity, associativity, commutativity when you put 4 blocks together). A trivial example of an indexed Monoid: the one where the index does not matter:
newtype Dummy (m :: *) (i :: k) = Dummy { getDummy :: m }
instance Monoid m => MonoidIx (Dummy m :: * -> *) where
type Null (Dummy m) = ()
type Mult (Dummy m) i j = ()
nullIx = Dummy mempty
multIx (Dummy i) (Dummy j) = Dummy $ mappend i j
I'll let you implement the instance for matrices ;)
Upvotes: 2