module 1Lab.Reflection.List where
Reflection utilities for listsπ
The following patterns are useful.
pattern `List `A = def (quote List) (unknown hβ· `A vβ· [])
pattern _`β·_ `x `xs = con (quote List._β·_) (unknown hβ· unknown hβ· `x vβ· `xs vβ· [])
pattern `[] = con (quote List.[]) (unknown hβ· unknown hβ· [])
pattern _`β·?_ `x `xs = con (quote List._β·_) (`x vβ· `xs vβ· [])
pattern `[]? = con (quote List.[]) []
We can quote lists of terms to get a quoted list, and we can unquote terms to lists of terms, so long as the spine of the list can be fully reduced.
: List Term β Term
quoteList = foldr _`β·_ `[]
quoteList
{-# TERMINATING #-}
: Term β TC (List Term)
unquoteList =
unquoteList `xs Ξ» where
reduce `xs >>= β pure []
`[] (`x `β· `xs) β `x β·_ <$> unquoteList `xs
(meta m _) β block-on-meta m
β typeError [ "unquoteList: can't unquote " , termErr `xs , " because it cannot be reduced to whnf." ] `xs
We also provide patterns for list membership.
pattern _`ββ_ `x `xs = def (quote _ββ_) (unknown hβ· unknown hβ· `x vβ· `xs vβ· [])
pattern `here `p = con (quote _ββ_.here) (unknown hβ· unknown hβ· unknown hβ· unknown hβ· `p vβ· [])
pattern `there `mem = con (quote _ββ_.there) (unknown hβ· unknown hβ· unknown hβ· unknown hβ· `mem vβ· [])
pattern `here? `p = con (quote _ββ_.here) (`p vβ· [])
pattern `there? `mem = con (quote _ββ_.there) (`mem vβ· [])
Proof automation for unique membershipπ
Writing proofs that is-contr (x ββ xs)
is a common but
tedious task, so we provide some macros for constructing them.
Our first helper function walks down a list, searching for an element while accumulating a term for the proof that the element is in the list, as well as patterns for matching that element and an absurd pattern.
private
find-member-with: (`x : Term) (`xs : Term) (spine : List Term)
β Term β Pattern β Pattern
β TC (Term Γ Pattern Γ Pattern Γ List Term)
=
find-member-with `x `xs [] `mem `found `not-found "has-member: could not find " , termErr `x , " in " , termErr `xs ]
typeError [ (`y β· spine) `mem `found `not-found =
find-member-with `x `xs Ξ» where
unifies? `x `y >>= β pure (`mem , `found , `not-found , spine)
true β
false (`there `mem) (`there? `found) (`there? `not-found) find-member-with `x `xs spine
Our second helper also iterates through the list, but instead constructs absurd clauses for each element.
private
refute-member-with: (`x : Term) (`xs : Term) (spine : List Term)
β Pattern β List Clause
β List Clause
= clauses
refute-member-with `x `xs [] `not-found clauses (`y β· spine) `not-found clauses =
refute-member-with `x `xs let `not-found-clause = absurd-clause (("_" , argN (`x `ββ `xs)) β· []) (`not-found vβ· [])
in refute-member-with `x `xs spine (`there? `not-found) (`not-found-clause β· clauses)
Our macro then calls these two helpers in sequence, and packages the
results into a contr
.
unique-member-worker: β {β} {A : Type β}
β (x : A) (xs : List A)
β Term
β TC β€
= do
unique-member-worker x xs hole
`x β quoteTC x
spine β traverse quoteTC xslet `xs = quoteList spine
(`mem , `found , `not-found , rest) β
find-member-with `x `xs spine(`here (con (quote reflα΅’) []))
(`here? (con (quote reflα΅’) []))
(`here? (absurd 0))
let clauses =
refute-member-with `x `xs rest(`there? `not-found)
(clause [] (`found vβ· []) (def (quote refl) []) β· [])
(con (quote contr) (`mem vβ· pat-lam clauses [] vβ· []))
unify hole
unique-member!: β {β} {A : Type β}
β {x : A} {xs : List A}
β {@(tactic unique-member-worker x xs) mem : is-contr (x ββ xs)}
β is-contr (x ββ xs)
{mem = mem} = mem unique-member!
We also get a macros for proving that an element is either in or not in a list en-passant.
private
member-worker: β {β} {A : Type β}
β (x : A) (xs : List A)
β Term
β TC β€
= do
member-worker x xs hole
`x β quoteTC x
spine β traverse quoteTC xslet `xs = quoteList spine
(`mem , _ , _ , _) β
find-member-with `x `xs spine(`here (con (quote reflα΅’) []))
(`here? (con (quote reflα΅’) []))
(`here? (absurd 0))
unify hole `mem
not-member-worker: β {β} {A : Type β}
β (x : A) (xs : List A)
β Term
β TC β€
= do
not-member-worker x xs hole
`x β quoteTC x
`xs β traverse quoteTC xslet clauses = refute-member-with `x (quoteList `xs) `xs (`here? (absurd 0)) []
(pat-lam clauses [])
unify hole
member!: β {β} {A : Type β}
β {x : A} {xs : List A}
β {@(tactic member-worker x xs) mem : x β xs}
β x β xs
{mem = mem} = mem
member!
not-member!: β {β} {A : Type β}
β {x : A} {xs : List A}
β {@(tactic not-member-worker x xs) not-mem : x β xs}
β x β xs
{not-mem = not-mem} = not-mem not-member!
Examplesπ
private
: true β [ false , true , false , true , false ]
member-example = member!
member-example
: true β [ false , false , false ]
not-member-example = not-member!
not-member-example
: is-contr (true β [ false , true , false , false ])
unique-member-example = unique-member! unique-member-example