{-# LANGUAGE FunctionalDependencies, TypeFamilies, AllowAmbiguousTypes #-} main :: IO () main = do pureId (putStrLn "hello") print =<< pureId True class PureId arg m where pureId :: arg -> Res m arg type family Res m a where Res n (m a) = m a Res m a = m a instance {-# OVERLAPPABLE #-} (Monad m, Res m a ~ m a) => PureId a m where pureId = pure instance (m ~ n) => PureId (m a) n where pureId = id