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)