Skip to content

Instantly share code, notes, and snippets.

@Icelandjack
Last active May 2, 2017 16:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Icelandjack/2cd92caca4bccd44651ed39034c3cde1 to your computer and use it in GitHub Desktop.
Save Icelandjack/2cd92caca4bccd44651ed39034c3cde1 to your computer and use it in GitHub Desktop.
Deriving

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)

Add

This should support

-- VALIDATION err = Sum Identity (Const err)

data VALIDATION err a = PURE a | ERR err
  deriving with LIFT (CONST err)
    (Functor, Applicative)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment