Existem várias maneiras de fazer o que você deseja. Uma delas é usar uma representação de sintaxe diferente sob a qualαtermos -equivalentes são realmente iguais. Tais representações têm o nome de sintaxe sem nome ou localmente sem nome . Um popular usa índices de Bruijn . Veja minhas postagens no blog Como implementar a teoria dos tipos dependentes I , II e III para uma introdução rápida à implementação desse tipo de coisa (a parte III explicou os índices de Bruijn).
Se você insistir em sua representação, ainda poderemos usar secretamente os índices de Bruijn, como a seguir. À medida que descemos dentro de um subtermo durante a comparação, mantemos uma lista de pares de variáveis ligadas encontradas até o momento. Por exemplo, ao comparar Forall x1 e1
e Forall x2 e2
, adicionamos o par (x1, x2)
à lista e comparamos recursivamente e1
e e2
. Quando solicitados a comparar variáveis x
e y
, procuramos na lista: ou elas devem aparecer no mesmo local (estavam vinculadas pelo mesmo quantificador) ou nenhuma aparecer e são iguais (são livres e são iguais).
Eu não sou bem versado em Haskell, mas você teria algo assim:
newtype Var = Var Int deriving Eq
data Term = Belong Var Var
| Bot
| Imply Term Term
| Forall Var Term
equalVar :: [(Var,Var)] -> Var -> Var -> Bool
equalVar [] x y = (x == y)
equalVar ((x,y):bound) z w = (x == z && y == w) || (x /= z && y /= w && equalVar bound z w)
equal' :: [(Var, Var)] -> Term -> Term -> Bool
equal' bound (Belong x1 y1) (Belong x2 y2) = (equalVar bound x1 x2 && equalVar bound y1 y2)
equal' bound Bot Bot = True
equal' bound (Imply u1 v1) (Imply u2 v2) = equal' bound u1 u2 && equal' bound v1 v2
equal' bound (Forall x u) (Forall y v) = equal' ((x,y):bound) u v
equal' _ _ _ = False
equal :: Term -> Term -> Bool
equal e1 e2 = equal' [] e1 e2