packages feed

rebound-0.1.0.0: src/Data/Scoped/Telescope.hs

-- |
-- Stability: experimental
{-# OPTIONS_HADDOCK hide #-}
module Data.Scoped.Telescope {-# WARNING "This module is experimental" #-} where

import Rebound.Classes
import Rebound.Env (Shiftable (..))
import Data.Fin (Fin)
import Data.Nat
import Data.Type.Equality ((:~:) (..))
import Data.Type.Nat
import Data.Vec.Lazy qualified as Vec
import Rebound.Lib (axiomAssoc, axiomPlusZ)
import Data.SNat

-- | Unlike 'Scoped.TeleList', this datatype does not nest: it is effectively a
-- 'List.List'/'Data.Vec.Vec' but with extra scoping inside.
data Telescope u s n m where
  TNil :: Telescope u s Z m
  TCons :: (u, s (n + m)) -> !(Telescope u s n m) -> Telescope u s (S n) m

tmap :: (forall k. u -> s k -> (u', s' k)) -> Telescope u s n m -> Telescope u' s' n m
tmap f TNil = TNil
tmap f (TCons (u, s) xs) = TCons (f u s) (tmap f xs)

empty :: Telescope u s Z m
empty = TNil

singleton :: (u, s n) -> Telescope u s (S Z) n
singleton h = TCons h TNil

append :: forall u s nl nr m. Telescope u s nl (nr + m) -> Telescope u s nr m -> (SNat nl, Telescope u s (nl + nr) m)
append TNil r = (SZ, r)
append (TCons l ls) r =
  case axiomAssoc @nl @nr @m of
    Refl -> let (k, ls') = append ls r in withSNat k (SS, TCons l ls')

toTelescope :: forall p n u s. (Shiftable s) => Vec.Vec p (u, s n) -> Telescope u s p n
toTelescope = snd . iter
  where
    iter :: forall p. Vec.Vec p (u, s n) -> (SNat p, Telescope u s p n)
    iter Vec.VNil = (SZ, TNil)
    iter ((Vec.:::) @_ @p' (u, s) xs) =
      let (sp', sc') :: (SNat p', Telescope u s p' n) = iter xs
          s' :: s (p' + n) = shift sp' s
       in (withSNat sp' SS, TCons (u, s') sc')

-- fromTelescope :: forall s u p n. (Shiftable s) => Telescope u s p n -> (SNat p, Vec.Vec p (u, s (p + n)))
-- fromTelescope = iter SZ
--   where
--     iter :: forall u s k n m. (Shiftable s) => SNat k -> Telescope u s n m -> (SNat (k + n), Vec.Vec n (u, s (k + n + m)))
--     iter sk TNil = case axiomPlusZ @k of Refl -> (sk, Vec.empty)
--     iter sk (TCons @_ @_ @n' (u, s) sc) =
--       case axiomSus @k @n' of
--         Refl ->
--           let x' :: (u, s (k + n + m)) = case axiomAssoc @k @n' @m of Refl -> (u, shift (addOne sk) s)
--               (sn', sc') :: (SNat (k + n), Vec.Vec n' (u, s (k + n + m))) = iter (addOne sk) sc
--            in (sn', x' Vec.::: sc')

--     addOne :: SNat k -> SNat (S k)
--     addOne k = withSNat k SS

emptyTelescope = TNil

-- nth :: forall s n m u. (Shiftable s) => Fin n -> Telescope u s n m -> (u, s (n + m))
-- nth i s = snd (fromTelescope s) Vec.! i

instance Sized (Telescope u s n m) where
  type Size (Telescope u s n m) = n
  size :: Telescope u s n m -> SNat n
  size TNil = s0
  size (TCons _ t) = withSNat (size t) SS