# LANGUAGE DefaultSignatures #
# LANGUAGE DeriveGeneric      #
# LANGUAGE FlexibleContexts   #
{-# LANGUAGE TypeFamilies      #-}
{-# LANGUAGE TypeOperators     #-}

module GenericsTutorial
  ( CountFields (..) )
where

import GHC.Generics
import Numeric.Natural
import Prelude

class CountFields a where
  -- | Return number of constructor fields for a value.
  countFields :: a -> Natural
  default countFields :: (Generic a, CountFields1 (Rep a)) => a -> Natural
  countFields = defaultCountFields

defaultCountFields :: (Generic a, CountFields1 (Rep a)) => a -> Natural
defaultCountFields = countFields1 . from

class CountFields1 f where
  countFields1 :: f p -> Natural

instance CountFields1 V1 where
  countFields1 _ = 0

instance CountFields1 U1 where
  countFields1 _ = 0

instance CountFields1 (K1 i c) where
  countFields1 _ = 1

instance CountFields1 f => CountFields1 (M1 i c f) where
  countFields1 (M1 x) = countFields1 x

instance (CountFields1 a, CountFields1 b) => CountFields1 (a :+: b) where
  countFields1 (L1 x) = countFields1 x
  countFields1 (R1 x) = countFields1 x

instance (CountFields1 a, CountFields1 b) => CountFields1 (a :*: b) where
  countFields1 (a :*: b) = countFields1 a + countFields1 b

----------------------------------------------------------------------------
-- Tests

instance CountFields (Maybe a)

data Foo = Foo Int Int Int | Bar Bool
  deriving (Show, Generic)

instance CountFields Foo

# LANGUAGE TypeFamilies      #
# LANGUAGE TypeOperators     #
 | Return number of constructor fields for a value.
--------------------------------------------------------------------------
 Tests
# LANGUAGE DefaultSignatures #
# LANGUAGE DeriveGeneric      #
# LANGUAGE FlexibleContexts   #

module GenericsTutorial
  ( CountFields (..) )
where

import GHC.Generics
import Numeric.Natural
import Prelude

class CountFields a where
  countFields :: a -> Natural
  default countFields :: (Generic a, CountFields1 (Rep a)) => a -> Natural
  countFields = defaultCountFields

defaultCountFields :: (Generic a, CountFields1 (Rep a)) => a -> Natural
defaultCountFields = countFields1 . from

class CountFields1 f where
  countFields1 :: f p -> Natural

instance CountFields1 V1 where
  countFields1 _ = 0

instance CountFields1 U1 where
  countFields1 _ = 0

instance CountFields1 (K1 i c) where
  countFields1 _ = 1

instance CountFields1 f => CountFields1 (M1 i c f) where
  countFields1 (M1 x) = countFields1 x

instance (CountFields1 a, CountFields1 b) => CountFields1 (a :+: b) where
  countFields1 (L1 x) = countFields1 x
  countFields1 (R1 x) = countFields1 x

instance (CountFields1 a, CountFields1 b) => CountFields1 (a :*: b) where
  countFields1 (a :*: b) = countFields1 a + countFields1 b


instance CountFields (Maybe a)

data Foo = Foo Int Int Int | Bar Bool
  deriving (Show, Generic)

instance CountFields Foo
