-- |
-- Module      : Generics.Deriving.Default
-- Description : Default implementations of generic classes
-- License     : BSD-3-Clause
--
-- Maintainer  : generics@haskell.org
-- Stability   : experimental
-- Portability : non-portable
--
-- GHC 8.6 introduced the
-- @<https://downloads.haskell.org/~ghc/8.6.3/docs/html/users_guide/glasgow_exts.html?highlight=derivingvia#extension-DerivingVia DerivingVia>@
-- language extension, which means a typeclass instance can be derived from
-- an existing instance for an isomorphic type. Any newtype is isomorphic
-- to the underlying type. By implementing a typeclass once for the newtype,
-- it is possible to derive any typeclass for any type with a 'Generic' instance.
--
-- For a number of classes, there are sensible default instantiations. In
-- older GHCs, these can be supplied in the class definition, using the
-- @<https://downloads.haskell.org/~ghc/8.6.3/docs/html/users_guide/glasgow_exts.html?highlight=defaultsignatures#extension-DefaultSignatures DefaultSignatures>@
-- extension. However, only one default can be provided! With
-- @<https://downloads.haskell.org/~ghc/8.6.3/docs/html/users_guide/glasgow_exts.html?highlight=derivingvia#extension-DerivingVia DerivingVia>@
-- it is now possible to choose from many
-- default instantiations.
--
-- This package contains a number of such classes. This module demonstrates
-- how one might create a family of newtypes ('Default', 'Default1') for
-- which such instances are defined.
--
-- One might then use
-- @<https://downloads.haskell.org/~ghc/8.6.3/docs/html/users_guide/glasgow_exts.html?highlight=derivingvia#extension-DerivingVia DerivingVia>@
-- as follows. The implementations of the data types are elided here (they
-- are irrelevant). For most cases, either the deriving clause with the
-- data type definition or the standalone clause will work (for some types
-- it is necessary to supply the context explicitly using the latter form).
-- See the source of this module for the implementations of instances for
-- the 'Default' family of newtypes and the source of the test suite for
-- some types which derive instances via these wrappers.

{-# LANGUAGE CPP #-}
#if __GLASGOW_HASKELL__ >= 701
{-# LANGUAGE DefaultSignatures #-}
# if __GLASGOW_HASKELL__ >= 704
{-# LANGUAGE Safe #-}
# else
{-# LANGUAGE Trustworthy #-}
# endif
#endif
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}

module Generics.Deriving.Default
  ( -- * Kind @*@ (aka @Type@)

    -- $default

    Default(..)

  , -- * Kind @* -> *@ (aka @Type -> Type@)

    -- $default1

    Default1(..)

    -- * Other kinds

    -- $other-kinds
  ) where

#if !(MIN_VERSION_base(4,8,0))
import Control.Applicative ((<$>))
#endif
import Control.Monad (liftM)

import Generics.Deriving.Base
import Generics.Deriving.Copoint
import Generics.Deriving.Enum
import Generics.Deriving.Eq
import Generics.Deriving.Foldable
import Generics.Deriving.Functor
import Generics.Deriving.Monoid
import Generics.Deriving.Semigroup
import Generics.Deriving.Show
import Generics.Deriving.Traversable
import Generics.Deriving.Uniplate

-- $default
--
-- For classes which take an argument of kind 'Data.Kind.Type', use
-- 'Default'. An example of this class from @base@ would be 'Eq', or
-- 'Generic'.
--
-- These examples use 'GShow' and 'GEq'; they are interchangeable.
--
-- @
-- data MyType = …
--  deriving ('Generic')
--  deriving ('GEq') via ('Default' MyType)
--
-- deriving via ('Default' MyType) instance 'GShow' MyType
-- @
--
-- Instances may be parameterized by type variables.
--
-- @
-- data MyType1 a = …
--  deriving ('Generic')
--  deriving ('GShow') via ('Default' (MyType1 a))
--
-- deriving via 'Default' (MyType1 a) instance 'GEq' a => 'GEq' (MyType1 a)
-- @
--
-- These types both require instances for 'Generic'. This is because the
-- implementations of 'geq' and 'gshowsPrec' for @'Default' b@ have a @'Generic'
-- b@ constraint, i.e. the type corresponding to @b@ require a 'Generic'
-- instance. For these two types, that means instances for @'Generic' MyType@
-- and @'Generic' (MyType1 a)@ respectively.
--
-- It also means the 'Generic' instance is not needed when there is already
-- a generic instance for the type used to derive the relevant instances.
-- For an example, see the documentation of the 'GShow' instance for
-- 'Default', below.

-- | This newtype wrapper can be used to derive default instances for
-- classes taking an argument of kind 'Data.Kind.Type'.
newtype Default a = Default { forall a. Default a -> a
unDefault :: a }

-- $default1
--
-- For classes which take an argument of kind @'Data.Kind.Type' ->
-- 'Data.Kind.Type'@, use 'Default1'.  An example of this class from @base@
-- would be 'Data.Functor.Classes.Eq1', or 'Generic1'.
--
-- Unlike for @MyType1@, there can be no implementation of these classes for @MyType :: 'Data.Kind.Type'@.
--
-- @
-- data MyType1 a = …
--  deriving ('Generic1')
--  deriving ('GFunctor') via ('Default1' MyType1)
--
-- deriving via ('Default1' MyType1) instance 'GFoldable' MyType1
-- @
--
-- Note that these instances require a @'Generic1' MyType1@ constraint as
-- 'gmap' and 'gfoldMap' have @'Generic1' a@ constraints on the
-- implementations for @'Default1' a@.

-- | This newtype wrapper can be used to derive default instances for
-- classes taking an argument of kind @'Data.Kind.Type' -> 'Data.Kind.Type'@.
newtype Default1 f a = Default1 { forall (f :: * -> *) a. Default1 f a -> f a
unDefault1 :: f a }

-- $other-kinds
--
-- These principles extend to classes taking arguments of other kinds.

--------------------------------------------------------------------------------
-- Eq
--------------------------------------------------------------------------------

instance (Generic a, GEq' (Rep a)) => GEq (Default a) where
  -- geq :: Default a -> Default a -> Bool
  Default a
x geq :: Default a -> Default a -> Bool
`geq` Default a
y = a
x forall a. (Generic a, GEq' (Rep a)) => a -> a -> Bool
`geqdefault` a
y

--------------------------------------------------------------------------------
-- Enum
--------------------------------------------------------------------------------

-- | The 'Enum' class in @base@ is slightly different; it comprises 'toEnum' and
-- 'fromEnum'. "Generics.Deriving.Enum" provides functions 'toEnumDefault'
-- and 'fromEnumDefault'.
instance (Generic a, GEq a, Enum' (Rep a)) => GEnum (Default a) where
  -- genum :: [Default a]
  genum :: [Default a]
genum = forall a. a -> Default a
Default forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a x. Generic a => Rep a x -> a
to forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall {k} (f :: k -> *) (a :: k). Enum' f => [f a]
enum'

--------------------------------------------------------------------------------
-- Show
--------------------------------------------------------------------------------

-- | For example, with this type:
--
-- @
-- newtype TestShow = TestShow 'Bool'
--   deriving ('GShow') via ('Default' 'Bool')
-- @
--
-- 'gshow' for @TestShow@ would produce the same string as `gshow` for
-- 'Bool'.
--
-- In this example, @TestShow@ requires no 'Generic' instance, as the
-- constraint on 'gshowsPrec' from @'Default' 'Bool'@ is @'Generic' 'Bool'@.
--
-- In general, when using a newtype wrapper, the instance can be derived
-- via the wrapped type, as here (via @'Default' 'Bool'@ rather than @'Default'
-- TestShow@).
instance (Generic a, GShow' (Rep a)) => GShow (Default a) where
  -- gshowsPrec :: Int -> Default a -> ShowS
  gshowsPrec :: Int -> Default a -> ShowS
gshowsPrec Int
n (Default a
x) = forall a. (Generic a, GShow' (Rep a)) => Int -> a -> ShowS
gshowsPrecdefault Int
n a
x

--------------------------------------------------------------------------------
-- Semigroup
--------------------------------------------------------------------------------

-- | Semigroups often have many sensible implementations of
-- 'Data.Semigroup.<>' / 'gsappend', and therefore no sensible default.
-- Indeed, there is no 'GSemigroup'' instance for representations of sum
-- types.
--
-- In other cases, one may wish to use the existing wrapper newtypes in
-- @base@, such as the following (using 'Data.Semigroup.First'):
--
-- @
-- newtype FirstSemigroup = FirstSemigroup 'Bool'
--   deriving stock ('Eq', 'Show')
--   deriving ('GSemigroup') via ('Data.Semigroup.First' 'Bool')
-- @
--
instance (Generic a, GSemigroup' (Rep a)) => GSemigroup (Default a) where
  -- gsappend :: Default a -> Default a -> Default a
  Default a
x gsappend :: Default a -> Default a -> Default a
`gsappend` Default a
y = forall a. a -> Default a
Default forall a b. (a -> b) -> a -> b
$ a
x forall a. (Generic a, GSemigroup' (Rep a)) => a -> a -> a
`gsappenddefault` a
y

--------------------------------------------------------------------------------
-- Monoid
--------------------------------------------------------------------------------

instance (Generic a, GMonoid' (Rep a)) => GMonoid (Default a) where
  -- gmempty :: Default a
  gmempty :: Default a
gmempty = forall a. a -> Default a
Default forall a. (Generic a, GMonoid' (Rep a)) => a
gmemptydefault

  -- gmappend :: Default a -> Default a -> Default a
  Default a
x gmappend :: Default a -> Default a -> Default a
`gmappend` Default a
y = forall a. a -> Default a
Default forall a b. (a -> b) -> a -> b
$ a
x forall a. (Generic a, GMonoid' (Rep a)) => a -> a -> a
`gmappenddefault` a
y

--------------------------------------------------------------------------------
-- Uniplate
--------------------------------------------------------------------------------

instance (Generic a, Uniplate' (Rep a) a, Context' (Rep a) a) => Uniplate (Default a) where

  -- children   ::                                             Default a  ->   [Default a]
  -- context    ::                             Default a   -> [Default a] ->    Default a
  -- descend    ::            (Default a ->    Default a)  ->  Default a  ->    Default a
  -- descendM   :: Monad m => (Default a -> m (Default a)) ->  Default a  -> m (Default a)
  -- transform  ::            (Default a ->    Default a)  ->  Default a  ->    Default a
  -- transformM :: Monad m => (Default a -> m (Default a)) ->  Default a  -> m (Default a)

  children :: Default a -> [Default a]
children     (Default a
x)    =       forall a. a -> Default a
Default forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. (Generic a, Uniplate' (Rep a) a) => a -> [a]
childrendefault    a
x
  context :: Default a -> [Default a] -> Default a
context      (Default a
x) [Default a]
ys =       forall a. a -> Default a
Default  forall a b. (a -> b) -> a -> b
$  forall a. (Generic a, Context' (Rep a) a) => a -> [a] -> a
contextdefault     a
x    (forall a. Default a -> a
unDefault forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Default a]
ys)
  descend :: (Default a -> Default a) -> Default a -> Default a
descend    Default a -> Default a
f (Default a
x)    =       forall a. a -> Default a
Default  forall a b. (a -> b) -> a -> b
$  forall a. (Generic a, Uniplate' (Rep a) a) => (a -> a) -> a -> a
descenddefault          (forall a. Default a -> a
unDefault forall b c a. (b -> c) -> (a -> b) -> a -> c
. Default a -> Default a
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Default a
Default) a
x
  descendM :: forall (m :: * -> *).
Monad m =>
(Default a -> m (Default a)) -> Default a -> m (Default a)
descendM   Default a -> m (Default a)
f (Default a
x)    = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM forall a. a -> Default a
Default  forall a b. (a -> b) -> a -> b
$  forall a (m :: * -> *).
(Generic a, Uniplate' (Rep a) a, Monad m) =>
(a -> m a) -> a -> m a
descendMdefault   (forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM forall a. Default a -> a
unDefault forall b c a. (b -> c) -> (a -> b) -> a -> c
. Default a -> m (Default a)
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Default a
Default) a
x
  transform :: (Default a -> Default a) -> Default a -> Default a
transform  Default a -> Default a
f (Default a
x)    =       forall a. a -> Default a
Default  forall a b. (a -> b) -> a -> b
$  forall a. (Generic a, Uniplate' (Rep a) a) => (a -> a) -> a -> a
transformdefault        (forall a. Default a -> a
unDefault forall b c a. (b -> c) -> (a -> b) -> a -> c
. Default a -> Default a
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Default a
Default) a
x
  transformM :: forall (m :: * -> *).
Monad m =>
(Default a -> m (Default a)) -> Default a -> m (Default a)
transformM Default a -> m (Default a)
f (Default a
x)    = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM forall a. a -> Default a
Default  forall a b. (a -> b) -> a -> b
$  forall a (m :: * -> *).
(Generic a, Uniplate' (Rep a) a, Monad m) =>
(a -> m a) -> a -> m a
transformMdefault (forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM forall a. Default a -> a
unDefault forall b c a. (b -> c) -> (a -> b) -> a -> c
. Default a -> m (Default a)
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Default a
Default) a
x

--------------------------------------------------------------------------------
-- Functor
--------------------------------------------------------------------------------

instance (Generic1 f, GFunctor' (Rep1 f)) => GFunctor (Default1 f) where
  -- gmap :: (a -> b) -> (Default1 f) a -> (Default1 f) b
  gmap :: forall a b. (a -> b) -> Default1 f a -> Default1 f b
gmap a -> b
f (Default1 f a
fx) = forall (f :: * -> *) a. f a -> Default1 f a
Default1 forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b.
(Generic1 f, GFunctor' (Rep1 f)) =>
(a -> b) -> f a -> f b
gmapdefault a -> b
f f a
fx

--------------------------------------------------
-- Copoint
--------------------------------------------------

instance (Generic1 f, GCopoint' (Rep1 f)) => GCopoint (Default1 f) where
  -- gcopoint :: Default1 f a -> a
  gcopoint :: forall a. Default1 f a -> a
gcopoint = forall (d :: * -> *) a.
(Generic1 d, GCopoint' (Rep1 d)) =>
d a -> a
gcopointdefault forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a. Default1 f a -> f a
unDefault1

--------------------------------------------------
-- Foldable
--------------------------------------------------

instance (Generic1 t, GFoldable' (Rep1 t)) => GFoldable (Default1 t) where
  -- gfoldMap :: Monoid m => (a -> m) -> Default1 t a -> m
  gfoldMap :: forall m a. Monoid m => (a -> m) -> Default1 t a -> m
gfoldMap a -> m
f (Default1 t a
tx) = forall (t :: * -> *) m a.
(Generic1 t, GFoldable' (Rep1 t), Monoid m) =>
(a -> m) -> t a -> m
gfoldMapdefault a -> m
f t a
tx

--------------------------------------------------
-- Traversable
--------------------------------------------------

instance (Generic1 t, GFunctor' (Rep1 t), GFoldable' (Rep1 t), GTraversable' (Rep1 t)) => GTraversable (Default1 t) where
  -- gtraverse :: Applicative f => (a -> f b) -> Default1 t a -> f (Default1 t b)
  gtraverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Default1 t a -> f (Default1 t b)
gtraverse a -> f b
f (Default1 t a
fx) = forall (f :: * -> *) a. f a -> Default1 f a
Default1 forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (f :: * -> *) a b.
(Generic1 t, GTraversable' (Rep1 t), Applicative f) =>
(a -> f b) -> t a -> f (t b)
gtraversedefault a -> f b
f t a
fx