{-# OPTIONS_HADDOCK show-extensions #-}
-- |
-- Module     : Unbound.Generics.LocallyNameless.TH
-- Copyright  : (c) 2015, Aleksey Kliger
-- License    : BSD3 (See LICENSE)
-- Maintainer : Aleksey Kliger
-- Stability  : experimental
--
-- Template Haskell methods to construct instances of 'Alpha' for
-- datatypes that don't contain any names and don't participate in
-- 'Alpha' operations in any non-trivial way.
{-# LANGUAGE TemplateHaskell #-}
module Unbound.Generics.LocallyNameless.TH (makeClosedAlpha) where
import Language.Haskell.TH

import Control.Applicative (Applicative(..))
import Data.Monoid (Monoid(..))
import Unbound.Generics.LocallyNameless.Alpha (Alpha(..))

-- | Make a trivial @instance 'Alpha' T@ for a type @T@ that does not
-- contain any bound or free variable names
-- (or any in general any values that are themselves non-trivial
-- instances of 'Alpha').  Use this to write 'Alpha' instances for
-- types that you don't want to traverse via their @GHC.Generics.Rep@
-- representation just to find out that there aren't any names.
--
--
-- @
-- newtype T = T Int deriving (Eq, Ord, Show)
-- $(makeClosedAlpha T)
-- -- constructs
-- -- instance Alpha T where
-- --   aeq' _ = (==)
-- --   acompare' _ = compare
-- --   fvAny' _ _ = pure
-- --   close _ _ = id
-- --   open _ _ = id
-- --   isPat _ = mempty
-- --   isTerm _ = mempty
-- --   nthPatFind _ = mempty
-- --   namePatFind _ _ = mempty
-- --   swaps' _ _ = id
-- --   freshen' _ i = return (i, mempty)
-- --   lfreshen' _ i cont = cont i mempty
-- @
--
makeClosedAlpha :: Name -> DecsQ
makeClosedAlpha tyName = do

  let valueD vName e = valD (varP vName) (normalB e) []
      -- methods :: [Q Dec]
      methods =
             [
               valueD (mkName "aeq'")      [e| \_ctx        -> (==)               |]
             , valueD (mkName "fvAny'")    [e| \_ctx _nfn   -> pure               |]
             , valueD 'close               [e| \_ctx _b     -> id                 |]
             , valueD 'open                [e| \_ctx _b     -> id                 |]
             , valueD 'isPat               [e| \_           -> mempty             |]
             , valueD 'isTerm              [e| \_           -> mempty             |]
             , valueD 'nthPatFind          [e| \_           -> mempty             |]
             , valueD 'namePatFind         [e| \_           -> mempty             |]
             , valueD (mkName "swaps'")    [e| \_ctx _p     -> id                 |]
             , valueD (mkName "freshen'")  [e| \_ctx i      -> return (i, mempty) |]
             , valueD (mkName "lfreshen'") [e| \_ctx i cont -> cont i mempty      |]
             , valueD (mkName "acompare'") [e| \_ctx        -> compare            |]
             ]
  d <- instanceD (cxt []) (appT [t|Alpha|] (conT tyName)) methods
  return [d]