Shimuuar / monoid-statistics

Other
4 stars 1 forks source link

Wrappers for statistics of kind `Type -> Type` #3

Open o1lo01ol1o opened 4 years ago

o1lo01ol1o commented 4 years ago

I've written variations of the following types enough times to now raise an issue:

newtype Mean a = Mean {unMean :: StatM.MeanKBN}
    deriving stock (Eq, Generic)
    deriving newtype (Monoid, Semigroup)

newtype Count a = Count {unCount :: StatM.CountG Int}
    deriving stock (Eq, Generic)
    deriving newtype (Monoid, Semigroup)

newtype MinD a = MinD {unMinD :: StatM.MinD}
    deriving stock (Eq, Generic)
    deriving newtype (Monoid, Semigroup)

newtype MaxD a = MaxD {unMaxD :: StatM.MaxD}
    deriving stock (Eq, Generic)
    deriving newtype (Monoid, Semigroup)

instance (Real x) => StatM.StatMonoid (Mean x) x where
    addValue (Mean smp) !x = Mean (StatM.addValue smp x)
    singletonMonoid x = Mean (StatM.singletonMonoid x)
    {-# INLINE addValue        #-}
    {-# INLINE singletonMonoid #-}

instance StatM.StatMonoid (Count x) x where
    addValue (Count smp) !x = Count (StatM.addValue smp x)
    singletonMonoid x = Count (StatM.singletonMonoid x)
    {-# INLINE addValue        #-}
    {-# INLINE singletonMonoid #-}

instance StatM.StatMonoid (MinD Double) Double where
    addValue (MinD smp) !x = MinD (StatM.addValue smp x)
    singletonMonoid x = MinD (StatM.singletonMonoid x)
    {-# INLINE addValue        #-}
    {-# INLINE singletonMonoid #-}

instance StatM.StatMonoid (MaxD Double) Double where
    addValue (MaxD smp) !x = MaxD (StatM.addValue smp x)
    singletonMonoid x = MaxD (StatM.singletonMonoid x)
    {-# INLINE addValue        #-}
    {-# INLINE singletonMonoid #-}

The problem they look to solve is to get a "functorial" representation of the underlaying monoid so that it can be used in higher-kinded types (ie, barbies or vinyl).

data Foo f = Foo { foo :: f Double; bar :: f Double } 
  deriving stock (Generic)
  deriving anyclass (FunctorB, TraversableB, ApplicativeB, ConstraintsB)

deriving via (Barbie Foo f) instance AllBF Semigroup f Foo => Semigroup (Foo f)

deriving via (Barbie Foo f) instance AllBF Monoid f Foo => Monoid (Foo f)

type VinylFoo f = Rec f MyColumns

And easily access monoidal statistics:

type SummaryStats = Mean `Product`( Sum `Product` Count)

foo :: Foo SummaryStats
vinylFoo :: VinylFoo SummaryStats

meanPart :: Foo SummaryStats -> Foo Mean

meanBySumPart ::  VinylFoo SummaryStats -> VinylFoo (Mean `Product` Sum) 

etc.

I'm happy to open a PR if you have a good notion of how the above should be implemented.

(Bonus points for providing "accessors" to the various components in a generic way. This might have to be done using some of the machinery that already exists in barbies or vinyl though).

Shimuuar commented 4 years ago

One approach in to add instance

instance StatMonoid m a => StatMonoid (Const m x) a

Whenever I want to turn * into * -> * I usually reach for Const.

o1lo01ol1o commented 4 years ago

What about the newtypes themselves? Do those warrant inclusion in monoid-statistics?