One of the best parts of Haskell is getting functionality for free
newtype T a = T_ (Compose [] Maybe a)
deriving (Functor, Foldable, Traversable, Applicative, Alternative)
{-# Complete T #-}
pattern T :: [Maybe a] -> T a
pattern T a = T_ (Compose a)the more natural way of writing it does not let me derive Applicative, Alternative
newtype T a = T [Maybe a]I don’t want the instance resolution to be directed by my data type.
Quite often I have
data S a = S Int Int [a] [a] [a] [a] [a]
instance Semigroup (S a) where
(<>) :: S a -> S a -> S a
S a b c d e f g <> S a’ b’ c’ d’ e’ f’ g’ = S (a + a’) (b * b’) (c <> c’) (d <> d’) (e <> e’) (f <> f’) (g <> g’)
instance Monoid (S a) where
mempty :: S a
mempty = S 0 1 [] [] [] [] []Those Monoid/Semigroup instances are tedious, but the alternative is the ugly
newtype S a = S (Sum Int, Product Int, [a], [a], [a], [a], [a])
deriving (Semigroup, Monoid)So what do I propose? This information belongs as a deriving strategy, my vague idea is allowing first-class witnesses of the derivation tree, values that map between the sum-of-product (represented as [[Type]]) and a type that determines the GeneralizedNewtypeDeriving.
A simple example would be
-- Z (Cons Sum getSum (Cons Product getProduct Nil)) :: ‘[ ‘[ Int, Int ] ] <-> (Int, (Int, ())
data I a = I Int Int
deriving with Z (Cons Sum getSum (Cons Product getProduct Nil))
(Semigroup, Monoid)which will use the instances for (Sum Int, (Sum Product, ())), same goes for
-- Comp :: (f (g a) : xs) <-> Compose f g a
newtype T a = T [Maybe a]
deriving with Compose
(Functor, Foldable, Traversable, Applicative, Alternative)this is all hand-wavy
I do not want this to be limited to instances of sums of products, because there is no Applicative, Alternative instance for Sum but they exist as long as one of its summand is Identity (as in Lift).
data R a = Foo a | Bar [a]
deriving with Lift
(..., Applicative, Alternative)
data R’ a = Bar [a] | Foo a
deriving with Swap Lift
(..., Applicative, Alternative)In fact it is more complicated than that, as the post Abstracting with Applicatives states Sum f g is an Applicative whenever there is a (monoidal) natural transformation from f to g, it would be fantastic to support this!
Also from that same post
-- type Writer mo = Product (Const mo) Identity
-- type FailingWriter mo = Compose (Writer mo) Maybe
-- MUCH clearer
data Writer mo a = W mo a
deriving with ???
(..., Applicative)
data FailingWriter mo a = FW (Writer mo (Maybe a))
deriving with Compose ???
(..., Applicative)This should support
-- VALIDATION err = Sum Identity (Const err)
data VALIDATION err a = PURE a | ERR err
deriving with LIFT (CONST err)
(Functor, Applicative)