One of the problems is explained by Benjamin Hodgson in the comments. To do this, you just need to type the sameSymbol :
sameOrNotSymbol :: (KnownSymbol a, KnownSymbol b) => Proxy a -> Proxy b -> Either ((a == b) :~: 'False) (a :~: b) sameOrNotSymbol ss' = maybe (Left $ unsafeCoerce Refl) Right $ sameSymbol ss'
Then look can be defined as (assuming weak proved):
look :: (Lookup s xs ~ 'Just a, KnownSymbol s) => Proxy s -> HList xs -> Exp (DropWhileNotSame (s, a) xs) a look s ((s',p) :* rho) = case sameOrNotSymbol ss' of Left Refl -> weak s $ look s rho Right Refl -> p
The ambiguity error you get is related to the fact that s is mentioned in the constraints, but not defined anywhere. This is easy to fix - just specify Proxy s :
weak :: forall ss' xs a b. (KnownSymbol s , KnownSymbol s' , (s == s') ~ 'False) => Proxy s -> Exp xs a -> Exp ('(s', b) ': xs) a weak s (Val n) = Val n weak s (Var t) = ...
But here we are faced with a problem that is much more difficult to fix. What if the character stored in this Exp xs a matches the character s' , the character preceding the list? The return of Var t would be incorrect in this case, because the value of Var t was changed: it no longer denotes a symbol somewhere in the middle of the list - now it is in the head. And it does not print correctly, because it requires a and b be of the same type. Thus, this type of version checks:
weak :: forall ss' xs a a. (KnownSymbol s , KnownSymbol s' , (s == s') ~ 'False) => Proxy s -> Exp xs a -> Exp ('(s', a) ': xs) a weak s (Val n) = Val n weak s (Var t) = case sameOrNotSymbol t (Proxy :: Proxy s') of Left Refl -> Var t Right Refl -> Var (Proxy :: Proxy s')
but the one you desire does not. "But we know that the stored character cannot be s' , because this situation is explicitly refuted by defining look " - you can say. Good luck to prove it.
Just use the Bruijn indexes, really.