{-# LANGUAGE ScopedTypeVariables      #-}
{-# LANGUAGE TypeOperators            #-}
{-# LANGUAGE FlexibleContexts         #-}
{-# LANGUAGE OverlappingInstances     #-}
{-# LANGUAGE FlexibleInstances        #-}
{-# LANGUAGE GADTs                    #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Generics.Instant.Functions.Empty
-- Copyright   :  (c) 2010, Universiteit Utrecht
-- License     :  BSD3
--
-- Maintainer  :  generics@haskell.org
-- Stability   :  experimental
-- Portability :  non-portable
--
-- Generically produce a single finite value of a datatype.
--
-----------------------------------------------------------------------------

module Generics.Instant.Functions.Empty (
    Empty(..), empty,
    HasRec(..)
  ) where

import Generics.Instant.Base
import Generics.Instant.Instances ()

-- Generic empty on Representable (worker)
class Empty a where
  empty' :: a

instance Empty U where
  empty' = U
  
instance (HasRec a, Empty a, Empty b) => Empty (a :+: b) where
  empty' = if hasRec' (empty' :: a) then R empty' else L empty'
  
instance (Empty a, Empty b) => Empty (a :*: b) where
  empty' = empty' :*: empty'
  
instance (Empty a) => Empty (CEq c p p a) where
  empty' = C empty'

instance (Empty a) => Empty (Var a) where
  empty' = Var empty'

instance (Empty a) => Empty (Rec a) where
  empty' = Rec empty'

instance Empty Int where
  empty' = 0

instance Empty Integer where
  empty' = 0

instance Empty Float where
  empty' = 0

instance Empty Double where
  empty' = 0

instance Empty Char where
  empty' = '\NUL'
  
instance Empty Bool where
  empty' = False


-- Dispatcher
empty :: (Representable a, Empty (Rep a)) => a
empty = to empty'

-- Adhoc instances
-- none

-- Generic instances
instance (Empty a) => Empty (Maybe a)       where empty' = empty
instance (Empty a) => Empty [a]             where empty' = empty
instance (Empty a, Empty b) => Empty (a,b)  where empty' = empty


--------------------------------------------------------------------------------
-- | We use 'HasRec' to check for recursion in the structure. This is used 
-- to avoid selecting a recursive branch in the sum case for 'Empty'.
class HasRec a where
  hasRec' :: a -> Bool
  hasRec' _ = False
  
instance HasRec U
instance HasRec (Var a)

instance (HasRec a, HasRec b) => HasRec (a :*: b) where
  hasRec' (a :*: b) = hasRec' a || hasRec' b
  
instance (HasRec a, HasRec b) => HasRec (a :+: b) where
  hasRec' (L x) = hasRec' x
  hasRec' (R x) = hasRec' x

instance (HasRec a) => HasRec (CEq c p q a) where
  hasRec' (C x) = hasRec' x
  
instance HasRec (Rec a) where
  hasRec' _ = True
  
instance HasRec Int
instance HasRec Integer
instance HasRec Float
instance HasRec Double
instance HasRec Char