content: {- |
  Module      :  Control.Comonad.Sheet.Names
  Description :  Names for the relevant aspects of some smaller dimensions (currently up to 4).
  Copyright   :  Copyright (c) 2014 Kenneth Foner
  
  Maintainer  :  kenneth.foner@gmail.com
  Stability   :  experimental
  Portability :  non-portable
  
  This module defines names to be used manipulating n-dimensional sheets. Currently, names are defined for dimensions
  of 4 and fewer. Below is a summary of the names currently defined in this module. Template Haskell to define these names for new dimension numbers is coming soon!
  
  =Dimension 1:
  
     * 'Sheet1' is the type of a 1-dimensional sheet
  
     * 'left' (negative) and 'right' (positive) are directions
  
     * 'leftBy' and 'rightBy' define relative position by some integer argument
  
     * 'columnAt' defines absolute position at a given column
  
     * 'column' retrieves the current column index
  
     * 'd1' coerces a 1-or-fewer-dimensional reference to a 1-dimensional reference
  
  =Dimension 2:
     
     * 'Sheet2' is the type of a 2-dimensional sheet
  
     * 'above' (negative) and 'below' (positive) are directions
  
     * 'aboveBy' and 'belowBy' define relative position by some integer argument
  
     * 'rowAt' defines absolute position at a given row
  
     * 'row' retrieves the current row index
  
     * 'd2' coerces a 2-or-fewer-dimensional reference to a 2-dimensional reference
  
  =Dimension 3:
  
     * 'Sheet3' is the type of a 3-dimensional sheet
  
     * 'inward' (negative) and 'outward' (positive) are directions
  
     * 'inwardBy' and 'outwardBy' define relative position by some integer argument
  
     * 'levelAt' defines absolute position at a given level
  
     * 'level' retrieves the current level index
  
     * 'd3' coerces a 3-or-fewer-dimensional reference to a 3-dimensional reference
  
  =Dimension 4:
  
     * 'Sheet4' is the type of a 4-dimensional sheet
  
     * 'ana' (negative) and 'kata' (positive) are directions
  
     * 'anaBy' and 'kataBy' define relative position by some integer argument
  
     * 'spaceAt' defines absolute position at a given space
  
     * 'space' retrieves the current space index
  
     * 'd4' coerces a 4-or-fewer-dimensional reference to a 4-dimensional reference
  
  -}
  
  {-# LANGUAGE DataKinds        #-}
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE TypeFamilies     #-}
  {-# LANGUAGE TypeOperators    #-}
  
  module Control.Comonad.Sheet.Names
     ( Sheet1 , here1 , d1 , columnAt , column , rightBy , leftBy , right , left
     , Sheet2 , here2 , d2 , rowAt , row , aboveBy , belowBy , above , below
     , Sheet3 , here3 , d3 , levelAt , level , inwardBy , outwardBy , inward , outward
     , Sheet4 , here4 , d4 , spaceAt , space , anaBy , kataBy , ana , kata
     ) where
  
  import Control.Comonad.Sheet.Reference
  import Data.Numeric.Witness.Peano
  import Data.Stream.Tape
  import Control.Comonad.Sheet.Indexed
  import Data.Functor.Nested
  import Data.List.Indexed
  
  -- One dimension...
  
  type Rel1 = Relative :-: Nil
  type Nat1 = Succ Zero
  
  nat1 :: Natural Nat1
  nat1 = reifyNatural
  
  type Sheet1  = Nested  (NestedNTimes Nat1 Tape)
  type ISheet1 = Indexed (NestedNTimes Nat1 Tape)
  
  here1 :: RefList Rel1
  here1 = Rel 0 :-: ConicNil
  
  d1 :: (CombineRefLists Rel1 x) => RefList x -> RefList (Rel1 & x)
  d1 = (here1 &)
  
  columnAt :: Int -> RefList (Absolute :-: Nil)
  columnAt = dimensional nat1 . Abs
  
  column :: (Zero < NestedCount ts) => Indexed ts x -> Int
  column = getRef . nth Zero . index
  
  rightBy, leftBy :: Int -> RefList Rel1
  rightBy = dimensional nat1 . Rel
  leftBy = rightBy . negate
  
  right, left :: RefList Rel1
  right = rightBy 1
  left  = leftBy  1
  
  -- Two dimensions...
  
  type Rel2 = Relative :-: Rel1
  type Nat2 = Succ Nat1
  
  nat2 :: Natural Nat2
  nat2 = reifyNatural
  
  type Sheet2  = Nested  (NestedNTimes Nat2 Tape)
  type ISheet2 = Indexed (NestedNTimes Nat2 Tape)
  
  here2 :: RefList Rel2
  here2 = Rel 0 :-: here1
  
  d2 :: (CombineRefLists Rel2 x) => RefList x -> RefList (Rel2 & x)
  d2 = (here2 &)
  
  rowAt :: Int -> RefList (Tack Absolute Rel1)
  rowAt = dimensional nat2 . Abs
  
  row :: (Nat1 < NestedCount ts) => Indexed ts x -> Int
  row = getRef . nth nat1 . index
  
  belowBy, aboveBy :: Int -> RefList Rel2
  belowBy = dimensional nat2 . Rel
  aboveBy = belowBy . negate
  
  below, above :: RefList Rel2
  below = belowBy 1
  above = aboveBy 1
  
  -- Three dimensions...
  
  type Rel3 = Relative :-: Rel2
  type Nat3 = Succ Nat2
  
  nat3 :: Natural Nat3
  nat3 = reifyNatural
  
  type Sheet3  = Nested  (NestedNTimes Nat3 Tape)
  type ISheet3 = Indexed (NestedNTimes Nat3 Tape)
  
  here3 :: RefList Rel3
  here3 = Rel 0 :-: here2
  
  d3 :: (CombineRefLists Rel3 x) => RefList x -> RefList (Rel3 & x)
  d3 = (here3 &)
  
  levelAt :: Int -> RefList (Tack Absolute Rel2)
  levelAt = dimensional nat3 . Abs
  
  level :: (Nat2 < NestedCount ts) => Indexed ts x -> Int
  level = getRef . nth nat2 . index
  
  outwardBy, inwardBy :: Int -> RefList Rel3
  outwardBy = dimensional nat3 . Rel
  inwardBy  = outwardBy . negate
  
  outward, inward :: RefList Rel3
  outward = outwardBy 1
  inward  = inwardBy  1
  
  -- Four dimensions...
  
  type Rel4 = Relative :-: Rel3
  type Nat4 = Succ Nat3
  
  nat4 :: Natural Nat4
  nat4 = reifyNatural
  
  type Sheet4  = Nested  (NestedNTimes Nat4 Tape)
  type ISheet4 = Indexed (NestedNTimes Nat4 Tape)
  
  here4 :: RefList Rel4
  here4 = Rel 0 :-: here3
  
  d4 :: (CombineRefLists Rel4 x) => RefList x -> RefList (Rel4 & x)
  d4 = (here4 &)
  
  spaceAt :: Int -> RefList (Tack Absolute Rel3)
  spaceAt = dimensional nat4 . Abs
  
  space :: (Nat3 < NestedCount ts) => Indexed ts x -> Int
  space = getRef . nth nat3 . index
  
  anaBy, kataBy :: Int -> RefList Rel4
  anaBy  = dimensional nat4 . Rel
  kataBy = anaBy . negate
  
  ana, kata :: RefList Rel4
  ana  = anaBy  1
  kata = kataBy 1
  