We can turn to Daan Leijen HMF for a few ideas. (It deals with binders for "foralls", which also occur as commutative ones.
In particular, he rechecks the variables in the order they appear in the body.
Then a comparison of terms involves simultaneously sliding and comparing the results.
We can do this better by replacing this skolemization pass with a locally nameless view .
data Bound ta = Bound {-
So, now the occurrences of Bound under the lambda are variables connected directly by the lambda, as well as any type information that you want to insert, here I just used ().
Now, closed terms are polymorphic in 'a', and if you sort lambda elements on your site (and you can guarantee that you can always canonicalize lambda by removing unused terms) alpha-equivalent terms are compared simply with (==), and if you need open terms, you can work with Expr String or some other representation.
A more anal retentive version of the signature for Expr and Bound will use the existential type and the level type natural to determine the number of related variables and use the βFinβ in the Bound constructor, but since you must already maintain the invariant, you are binding more variables than # occurring in lambda, and that type information matches all Var (Bound n _) with the same n , which is not too important to maintain another.
Update. You can use my bound package to make it a better version in a completely autonomous way!
source share