rebound-0.1.0.0: src/Rebound/Bind/Pat.hs
-- |
-- Module : Rebound.Bind.Pat
-- Description : Bind variables according to a pattern
--
-- Bind variables according to a user-defined pattern.
module Rebound.Bind.Pat
( module Rebound,
type Bind,
bind,
unbind,
unbindl,
getPat,
getBody,
instantiate,
bindWith,
unbindWith,
instantiateWith,
applyUnder,
type Rebind (..),
type PatList (..),
lengthPL,
)
where
import Rebound
import qualified Data.Fin as Fin
import qualified Data.Vec as Vec
import Data.Set (Set)
import qualified Data.Set as Set
----------------------------------------------------------
-- * Bind type
----------------------------------------------------------
-- | Type binding 'Size pat' variables.
-- This data structure includes a delayed
-- substitution for the variables in the body of the binder.
data Bind v c (pat :: Type) (n :: Nat) where
Bind :: pat -> Env v m n -> c (Size pat + m) -> Bind v c pat n
-- | To compare pattern binders, we need to unbind, but also
-- first make sure that the patterns are equal.
instance (Eq pat, Sized pat, forall n. Eq (c n), Subst v c) => Eq (Bind v c pat n) where
b1 == b2 =
getPat b1 == getPat b2
&& getBody b1 == getBody b2
-- | Bind a pattern, using the identity substitution.
bind ::
(Sized pat, Subst v c) =>
pat ->
c (Size pat + n) ->
Bind v c pat n
bind pat = Bind pat idE
-- | Bind a pattern, while suspending the provided substitution.
bindWith :: pat -> Env v m n -> c (Size pat + m) -> Bind v c pat n
bindWith = Bind
-- | Retrieve the pattern of the binding.
getPat :: Bind v c pat n -> pat
getPat (Bind pat env t) = pat
-- | Retrieve the body of the binding.
getBody ::
forall v c pat n.
(Sized pat, Subst v c) =>
Bind v c pat n ->
c (Size pat + n)
getBody (Bind (pat :: pat) (env :: Env v m n) t) =
applyOpt applyE (upN (size pat) env) t
-- | Run a function on the body (and pattern), after applying the delayed substitution.
-- The size of the (current) scope is made available at runtime.
unbind ::
forall v c pat n d.
(SNatI n, Sized pat, Subst v v, Subst v c) =>
Bind v c pat n ->
((SNatI (Size pat + n)) => pat -> c (Size pat + n) -> d) ->
d
unbind bnd f =
withSNat (sPlus (size (getPat bnd)) (snat @n)) $
f (getPat bnd) (getBody bnd)
-- | Retrieve the body, as well as the bound pattern.
unbindl :: (Sized pat, Subst v c) => Bind v c pat n -> (pat, c (Size pat + n))
unbindl bnd = (getPat bnd, getBody bnd)
-- | Instantiate the body (i.e. replace the bound variables) with the provided terms.
instantiate ::
forall v c pat n.
(Sized pat, Subst v c) =>
Bind v c pat n ->
Env v (Size pat) n ->
c n
instantiate b e =
unbindWith
b
(\p r t -> applyOpt applyE (withSNat (size p) $ e .++ r) t)
-- | Apply a function under the binder.
-- The delayed substitution is __not__ applied, but is passed to the function instead.
applyUnder ::
(Sized pat, Subst v c2) =>
(forall m. Env v m (Size pat + n2) -> c1 m -> c2 (Size pat + n2)) ->
Env v n1 n2 ->
Bind v c1 pat n1 ->
Bind v c2 pat n2
applyUnder f r2 (Bind p r1 t) =
Bind p idE (f r' t)
where
r' = upN (size p) (r1 .>> r2)
-- | Run a function on the body.
-- The delayed substitution is __not__ applied, but is passed to the function instead.
unbindWith ::
(Sized pat, SubstVar v) =>
Bind v c pat n ->
(forall m. pat -> Env v m n -> c (Size pat + m) -> d) ->
d
unbindWith (Bind pat (r :: Env v m n) t) f =
f pat r t
-- | Instantiate the body (i.e. replace the bound variable) with the provided term.
-- The delayed substitution is __not__ applied, but is passed to the function instead.
instantiateWith ::
(Sized pat, SubstVar v) =>
Bind v c pat n ->
Env v (Size pat) n ->
(forall m. Env v m n -> c m -> c n) ->
c n
instantiateWith b v f = unbindWith b (\p r e -> withSNat (size p) $ f (v .++ r) e)
-----------------------------------------------------------------
-- instances for Bind (Subst, FV, Strengthen)
-----------------------------------------------------------------
-- | The substitution operation composes the explicit
-- substitution with the one stored at the binder
instance (SubstVar v) => Shiftable (Bind v c p) where
shift = shiftFromApplyE @v
instance (SubstVar v) => Subst v (Bind v c p) where
applyE :: Env v n m -> Bind v c p n -> Bind v c p m
applyE env1 (Bind p env2 m) = Bind p (env2 .>> env1) m
instance (Subst v c, Sized p, FV c) => FV (Bind v c p) where
appearsFree :: Fin n -> Bind v c p n -> Bool
appearsFree n b =
appearsFree (Fin.shiftN (size (getPat b)) n) (getBody b)
freeVars :: forall n. Bind v c p n -> Set (Fin n)
freeVars b = rescope (size (getPat b)) (freeVars (getBody b))
instance (Sized p, Subst v c, Strengthen c) => Strengthen (Bind v c p) where
strengthenRec ::
SNat k ->
SNat m ->
SNat n ->
Bind v c p (k + (m + n)) ->
Maybe (Bind v c p (k + n))
strengthenRec (k :: SNat k) (m :: SNat m) (n :: SNat n) bnd =
withSNat (sPlus k (sPlus m n)) $
unbind bnd $ \(p :: p) t' ->
case ( axiomAssoc @(Size p) @k @(m + n),
axiomAssoc @(Size p) @k @n
) of
(Refl, Refl) ->
bind p <$> strengthenRec (sPlus (size p) k) m n t'
-----------------------------------------------------------------
-- * Rebind type
---------------------------------------------------------------
data Rebind pat p2 n where
Rebind :: pat -> p2 (Size pat + n) -> Rebind pat p2 n
instance (SubstVar v, Sized p1, Subst v p2) => Shiftable (Rebind p1 p2) where
shift = shiftFromApplyE @v
instance (SubstVar v, Sized p1, Subst v p2) => Subst v (Rebind p1 p2) where
applyE :: Env v n m -> Rebind p1 p2 n -> Rebind p1 p2 m
applyE r (Rebind p1 p2) = Rebind p1 (applyE (upN (size p1) r) p2)
instance (Sized p1, FV p2) => FV (Rebind p1 p2) where
appearsFree :: (Sized p1, FV p2) => Fin n -> Rebind p1 p2 n -> Bool
appearsFree n (Rebind p1 p2) = appearsFree (Fin.shiftN (size p1) n) p2
freeVars :: (Sized p1, FV p2) => Rebind p1 p2 n -> Set (Fin n)
freeVars = undefined
instance (Sized p1, Strengthen p2) => Strengthen (Rebind p1 p2) where
strengthenRec (k :: SNat k) (m :: SNat m) (n :: SNat n) (Rebind (p1 :: p1) p2) =
case ( axiomAssoc @(Size p1) @k @(m + n),
axiomAssoc @(Size p1) @k @n
) of
(Refl, Refl) ->
Rebind p1 <$> strengthenRec (sPlus (size p1) k) m n p2
--------------------------------------------------------------
-- * Lists of patterns
--------------------------------------------------------------
-- | lists of patterns where variables at each position bind
-- later in the pattern
data PatList (pat :: Nat -> Type) p where
PNil :: PatList pat N0
PCons ::
(Size (pat p1) ~ p1) =>
pat p1 ->
PatList pat p2 ->
PatList pat (p2 + p1)
-- | The length of a pattern list is the number of patterns,
-- not the number of variables that it binds
lengthPL :: PatList pat p -> Int
lengthPL PNil = 0
lengthPL (PCons _ ps) = 1 + lengthPL ps
instance (forall n. Sized (pat n)) => Sized (PatList pat p) where
type Size (PatList pat p) = p
size PNil = s0
size (PCons (p1 :: pat p1) (p2 :: PatList pat p2)) =
sPlus @p2 @(Size (pat p1)) (size p2) (size p1)
instance
(forall p1 p2. PatEq (pat p1) (pat p2)) =>
PatEq (PatList pat p1) (PatList pat p2)
where
patEq :: PatList pat p1 -> PatList pat p2 -> Maybe (p1 :~: p2)
patEq PNil PNil = Just Refl
patEq (PCons p1 ps1) (PCons p2 ps2) = do
Refl <- patEq p1 p2
Refl <- patEq ps1 ps2
return Refl
patEq _ _ = Nothing
-- instance
-- (forall p n. WithData v (pat p) n) =>
-- WithData v (PatList pat p) n
-- where
-- extendWithData PNil = id
-- extendWithData (PCons (p1 :: pat p1') (ps :: PatList pat ps')) =
-- case axiomAssoc @ps' @p1' @n of
-- Refl -> extendWithData @v ps . extendWithData @v p1