Question

Where is the inner m quantified over?

@pash writes:

there's really no such thing as an "unquantified" type signature in Haskell.

Here's a program:

{-# LANGUAGE Haskell98, ScopedTypeVariables, InstanceSigs #-}
module Identity where

newtype IdentityT f a = IdentityT { runIdentityT :: f a }

instance Functor m => Functor (IdentityT m) where
    fmap f (IdentityT m) = IdentityT (fmap f m)

instance Applicative m => Applicative (IdentityT m) where
    pure x = IdentityT (pure x)
    IdentityT a <*> IdentityT b = IdentityT (a <*> b)

instance Monad m => Monad (IdentityT m) where
    (>>=) :: forall a b. IdentityT m a -> (a -> IdentityT m b) -> IdentityT m b
    IdentityT m >>= k =
      let
        f :: a -> m b
        f x =
          let IdentityT ran = k x
           in ran
      in
      IdentityT (f =<< m)

I can compile it with GHC 9.10.1 using ghc -c Identity.hs -fforce-recomp.

But note how the m isn't explicitly quantified over using a forall. I want to add the explicit quantification. Where does the inference algorithm add it? I thought it would add it to either the signature for f or for =<<. But if I add quantifications in either of those places, the program no longer compiles.

How do I remove implicit quantifications from the program?

 3  66  3
1 Jan 1970

Solution

 9

either the signature for f or for =<<.

Since the instance head is where m is first used, that is where the forall would be.

instance forall m. Monad m => Monad (IdentityT m) where

But note that the m in the signature of f isn't necessarily the same in the original program, since ScopedTypeVariables only applies if the m is forall'd. So if you add the scoping of the outer m (by using forall), the inner m is now constrained to be the same... I don't understand how come compilation fails if you change the inner type-level m to be n instead, i.e. f :: a -> n b.

EDIT: It seems that instance heads are treated specially, and the type variables may always be scoped there, if ScopedTypeVariables is on.

2024-07-21
Janus Troelsen