I can do code type checking with two relatively simple changes. However, I'm not quite sure if they are valid in the wider context of all your code.
Firstly, the eqIx type eqIx not use existing knowledge, namely that the env parameters are already known when you call it. We can change it to this, and it will still check the type - that is, we assume that the environments are the same, but the types of variables may not be the same.
eqIx :: Ix env a -> Ix env b -> Bool
After this change, it is important that eqIx tells us that the types of the two variables are actually the same. But only returning Bool , we hide it from the compiler. If instead we return the standard type equality certificate, we can distribute this information:
data EqWitness ab where IsEq :: EqWitness aa eqIx :: Ix env a -> Ix env b -> Maybe (EqWitness ab) eqIx ZeroIx ZeroIx = Just IsEq eqIx (SuccIx m) (SuccIx n) = eqIx mn eqIx _ _ = Nothing
(Probably some standard type for EqWitness for a hacker somewhere)
Now we can add PatternGuards and slightly modify your site to challenge the equality witness, if eqIx successful. This makes equality available for type checking in the body of the corresponding case:
fuse :: Dist env e1 -> Dist env e2 -> (Dist env e1, Dist env e2) fuse (ConcatMap f v@ (Var x)) (ConcatMap g (Var y)) | Just IsEq <- eqIx xy = let e = ConcatMap2 (f `mapBoth` g) v in (Fst e, Snd e) fuse e1 e2 = (e1, e2)
source share