DaanLeijenのHMFにいくつかのアイデアをアピールできます。(彼は「foralls」のバインダーを扱っていますが、これも可換として出くわします。
特に、本文の出現順に変数を再バインドします。
次に、用語の比較には、同じ方法でスコーレミングし、結果を比較することが含まれます。
そのスコーレム化パスをローカルで名前のない表現に置き換えることで、それよりもうまくいくことができます。
data Bound t a = Bound {-# UNPACK #-} !Int t | Unbound a
instance Functor (Bound t) where ...
instance Bifunctor Bound where ...
data Expr a
= Lambdas {-# UNPACK #-} !Int (Expr (Bound () a))
| Var a
したがって、ラムダの下でのBoundのオカレンスは、ラムダによって直接バウンドされる変数であり、オカレンスに入れたいタイプ情報とともに、ここでは()を使用しました。
これで、閉じた用語は「a」で多形になり、ラムダの要素を使用サイトで並べ替えると(未使用の用語を削除することでラムダを常に正規化できるようになります)、アルファに相当する用語は単純に(==)と比較されます。オープンタームが必要な場合は、ExprStringまたはその他の表現を使用できます。
ExprとBoundのシグネチャのより肛門性格のバージョンは、存在型と自然な型レベルを使用して、バインドされている変数の数を識別し、Boundコンストラクターで「Fin」を使用しますが、すでに不変条件を維持する必要があるためです。ラムダで発生する#よりも多くの変数をバインドしないこと、および型情報がすべてVar (Bound n _)
同じで一致すること、別の変数n
を維持するための負担はそれほど大きくないこと。
更新:私のbound
パッケージを使用して、完全に自己完結型の方法でこれの改善されたバージョンを実行できます!