Skip to content

Instantly share code, notes, and snippets.

@ChrisPenner
Last active February 22, 2019 19:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ChrisPenner/ccf1dab3d6c47713e639c7a8967755bc to your computer and use it in GitHub Desktop.
Save ChrisPenner/ccf1dab3d6c47713e639c7a8967755bc to your computer and use it in GitHub Desktop.
Derive Monoid for using Generics
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DeriveGeneric #-}
module GenericMonoid where
import Data.Monoid
import Data.Maybe
import Generics.OneLiner
import GHC.Generics
data MyThing = MyThing
{ fieldOne :: String
, fieldTwo :: Sum Int
} deriving Generic
gmempty :: forall a . (ADT a, Constraints a Monoid) => a
gmempty = head $ create @Monoid [mempty]
-- Note that this will fail if your type has multiple constructors 🤷‍♂️
gmappend :: forall a . (ADT a, Constraints a Semigroup) => a -> a -> a
gmappend a b =
fromJust $ zipWithA @Semigroup @a @Maybe (\a b -> Just (a <> b)) a b
instance Semigroup MyThing where
(<>) = gmappend
instance Monoid MyThing where
mempty = gmempty
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment