open import 1Lab.Reflection hiding (reverse)
open import 1Lab.Type
open import Data.Dec.Base
open import Data.Fin.Base
module 1Lab.Reflection.Variables where
--------------------------------------------------------------------------------
-- Variable Binding for Terms
--
-- Many reflection tasks will require us to construct abstract
-- syntax trees representing reified expressions, which we will
-- use to construct a normal form. This works fine up until we
-- need to start finding normal forms for equational theories
-- with some sort of commutativity. For instance, which expression
-- should we prefer: 'x + y' or 'y + x'?
--
-- The first solution we may try here is to impose some ordering on
-- `Term`, and then sort our lists. However, trying to define this
-- ordering is complex, and it's not even clear if we /can/ impose
-- a meaningful ordering.
--
-- The next solution is to try and order the variables by the
-- time they are /introduced/, which is what this module aims to do.
-- We introduce a type 'Variables', which is intended to be an abstract
-- source of variable expressions. This allows us to produce fresh
-- (already quoted) variables of type 'Fin', which can be inserted
-- into the syntax tree while it's being constructed.
--
-- Once the syntax trees have been completed, we can grab an
-- environment using the aptly named 'environment' function.
-- This returns a (already quoted) environment 'Vec A n',
-- which allows us to easily build up quoted
-- calls to our normalization functions rather easily.
-- We 🛐 the wisdom that reversing a list/vector is a type
-- error!
data Env {ℓ} (A : Type ℓ) : Nat → Type ℓ where
[] : Env A zero
_▷_ : ∀ {n} → Env A n → A → Env A (suc n)
record Variables {a} (A : Type a) : Type a where
constructor mk-variables
field
{nvars} : Nat
-- We store the bindings in reverse order so that it's
-- cheap to add a new one.
bound : Env A nvars
variables : Term → Maybe Term
open Variables
private variable
a b : Level
A : Type a
n : Nat
empty-vars : Variables A
empty-vars = mk-variables [] (λ _ → nothing)
private
bind : Term → Term → (Term → Maybe Term) → Term → Maybe Term
bind tm tm-var lookup tm' with lookup tm' | tm ≡? tm'
... | just tm'-var | _ = just tm'-var
... | nothing | yes _ = just tm-var
... | nothing | no _ = nothing
fzero' : ∀ {n} → Fin (suc n)
fzero' = fzero
fin-term : Nat → Term
fin-term zero = def (quote fzero') (unknown h∷ [])
fin-term (suc n) = def (quote fsuc) (unknown h∷ fin-term n v∷ [])
env-rec : (Mot : Nat → Type b) →
(∀ {n} → Mot n → A → Mot (suc n)) →
Mot zero →
Env A n → Mot n
env-rec Mot _▷*_ []* [] = []*
env-rec Mot _▷*_ []* (xs ▷ x) = env-rec (Mot ∘ suc) _▷*_ ([]* ▷* x) xs
reverse : Env A n → Vec A n
reverse {A = A} env = env-rec (Vec A) (λ xs x → x ∷ xs) [] env
-- Get the variable associated with a term, binding a new
-- one as need be. Note that this returns the variable
-- as a quoted term!
bind-var : Variables A → Term → TC (Term × Variables A)
bind-var vs tm with variables vs tm
... | just v = do
pure (v , vs)
... | nothing = do
a ← unquoteTC tm
let v = fin-term (nvars vs)
let vs' = mk-variables (bound vs ▷ a)
(bind tm v (variables vs))
pure (v , vs')
environment : Variables A → TC (Term × Term)
environment vs = do
env ← quoteTC (reverse (bound vs))
size ← quoteTC (nvars vs)
pure (size , env)