{-# LANGUAGE TypeFamilies, TemplateHaskell, EmptyDataDecls, TypeOperators #-}

{- |

Module      :  Type.Spine
Copyright   :  (c) The University of Kansas 2011
License     :  BSD3

Maintainer  :  nicolas.frisby@gmail.com
Stability   :  experimental
Portability :  see LANGUAGE pragmas (... GHC)

The spine-view on types.

-}
module Type.Spine (qK, Spine, TypeName, (:@), spineType) where

import Type.Spine.Kinds (parseK_, forallAppsK)
import Type.Spine.Stage0

import Language.Haskell.TH (Kind(ArrowK), tySynInstD, varT, mkName)
import Language.Haskell.TH.Quote (QuasiQuoter(..))

import Control.Monad ((<=<))



-- | @[qK|...|]@ is the a type that takes one parameter of the corresponding
-- kind. (The name is an encoding of that parameter's kind based on prefix
-- notation for application.)
qK :: QuasiQuoter
qK = QuasiQuoter (error "Type.Spine.qK Exp")
     (error "Type.Spine.qK Pat")
     (kTypeG <=< parseK_) (error "Type.Spine.qK Dec")

infixl 9 :@
-- | A type-level application.
data tc :@ t

fmap concat $ forallAppsK $ \ak k ->
  let kq = kTypeG k; aq = kTypeG ak; fq = kTypeG $ ArrowK ak k
      [f, a] = map (varT . mkName) ["f", "a"]
  in (:[]) `fmap` tySynInstD ''Spine [[t| $kq ($f $a) |]] [t| $fq $f :@ $aq $a |]





fmap concat $ mapM spineType
  [''Bool, ''Char, ''Double, ''Float, ''Int, ''Integer, ''Ordering,
   ''(), ''(,), ''(,,), ''(,,,), ''(,,,,),
   ''IO, ''[], ''Maybe, ''(->), ''Either]