{-# LANGUAGE TypeOperators            #-}
{-# LANGUAGE TypeFamilies             #-}
{-# LANGUAGE StandaloneDeriving       #-}
{-# LANGUAGE GADTs                    #-}
{-# LANGUAGE FlexibleInstances        #-}
{-# LANGUAGE EmptyDataDecls           #-}
{-# LANGUAGE DataKinds                #-}
{-# LANGUAGE PolyKinds                #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Generics.Instant.Base
-- Copyright   :  (c) 2010, Universiteit Utrecht
-- License     :  BSD3
--
-- Maintainer  :  generics@haskell.org
-- Stability   :  experimental
-- Portability :  non-portable
--
-- This module defines the basic representation types and the conversion
-- functions 'to' and 'from'. A typical instance for a user-defined datatype
-- would be:
-- 
-- > -- Example datatype
-- > data Exp = Const Int | Plus Exp Exp
-- >
-- > -- Auxiliary datatypes for constructor representations
-- > data Const
-- > data Plus
-- > 
-- > instance Constructor Const where conName _ = "Const"
-- > instance Constructor Plus  where conName _ = "Plus"
-- > 
-- > -- Representable instance
-- > instance Representable Exp where
-- >   type Rep Exp = C Const (Var Int) :+: C Plus (Rec Exp :*: Rec Exp)
-- > 
-- >   from (Const n)   = L (C (Var n))
-- >   from (Plus e e') = R (C (Rec e :*: Rec e'))
-- > 
-- >   to (L (C (Var n)))            = Const n
-- >   to (R (C (Rec e :*: Rec e'))) = Plus e e'
-- 
-----------------------------------------------------------------------------

module Generics.Instant.Base (
      Z, U(..), (:+:)(..), (:*:)(..), CEq(..), C, Var(..), Rec(..)
    , Constructor(..), Fixity(..), Associativity(..)
    , Representable(..)
    , X, Nat(..)
  ) where

infixr 5 :+:
infixr 6 :*:

data Z
data U       = U              deriving (Show, Read)
data a :+: b = L a | R b      deriving (Show, Read)
data a :*: b = a :*: b        deriving (Show, Read)
data Var a   = Var a          deriving (Show, Read)
data Rec a   = Rec a          deriving (Show, Read)

data CEq c p q a where C :: a -> CEq c p p a
deriving instance (Show a) => Show (CEq c p q a)
deriving instance (Read a) => Read (CEq c p p a)

-- Shorthand when no proofs are required
type C c a = CEq c () () a

-- | Class for datatypes that represent data constructors.
-- For non-symbolic constructors, only 'conName' has to be defined.
class Constructor c where
  conName   :: t c p q a -> String
  {-# INLINE conFixity #-}
  conFixity :: t c p q a -> Fixity
  conFixity = const Prefix
  {-# INLINE conIsRecord #-}
  conIsRecord :: t c p q a -> Bool
  conIsRecord = const False

-- | Datatype to represent the fixity of a constructor. An infix declaration
-- directly corresponds to an application of 'Infix'.
data Fixity = Prefix | Infix Associativity Int
  deriving (Eq, Show, Ord, Read)

-- | Datatype to represent the associativy of a constructor.
data Associativity = LeftAssociative | RightAssociative | NotAssociative
  deriving (Eq, Show, Ord, Read)


class Representable a where
  type Rep a
  to   :: Rep a -> a
  from :: a -> Rep a
  -- defaults
  {-
  type Rep a = a -- type synonyms defaults are not yet implemented!
  to   = id
  from = id
  -}

-- Type family for representing existentially-quantified variables
type family X c (n :: Nat) (a :: k1) :: k2

-- Natural numbers, to be used at the type level
data Nat = Ze | Su Nat