What's interfering with my scoped type variables here?

105 Views Asked by At

I've been dreading asking this question for the last couple of days since it has the hallmarks of me not noticing a small mistake, so I sincerely apologize if that is the case.

I am trying to write my own scanr as a part of a library I am writing. The code looks like the following:

-- Language Extensions for the file --
{-# Language BangPatterns #-}
{-# Language FlexibleInstances #-}
{-# Language FlexibleContexts #-}
{-# Language QuantifiedConstraints #-}
{-# Language UndecidableInstances #-}
{-# Language ScopedTypeVariables #-}

rightScan ::
  ( Foldable f
  )
    => forall a b . (a -> b -> b) -> b -> f a -> NonEmpty [] b
rightScan g start as = start :| reverse (rightFold addOn [] as)
  where
    addOn :: a -> [b] -> [b]
    addOn new (c : cs) = g new c : c : cs
    addOn new [] = [g new start]

(My NonEmpty is actually parameterized by a container (in this case []), my NonEmpty [] is equivalent to the traditional NonEmpty.)

Now this has an two errors:

• Couldn't match expected type ‘a’ with actual type ‘a1’
  ‘a1’ is a rigid type variable bound by
    the type signature for:
      addOn :: forall a1 b1. a1 -> [b1] -> [b1]

and the very similar

• Couldn't match expected type ‘b’ with actual type ‘b1’
  ‘b1’ is a rigid type variable bound by
    the type signature for:
      addOn :: forall a1 b1. a1 -> [b1] -> [b1]

Now these errors are pretty easy to understand. It considers the a in rightScran's signature to be different from a in addOn's signature and the same with b. However I have scoped type variables on and both those variables are introduced with a forall in the parent.

Now I can just remove the signature of addOn to resolve the issue, but I am utterly baffled as to why scoped type variables is not working here.

So the question is: What am I doing wrong with my scoped type variables here?

1

There are 1 best solutions below

1
On BEST ANSWER

The problem is the location of the forall. It needs to come before the constraint and list all type variables, including f. forall f a b. (Foldable f) => ....

The way you've written it, the forall doesn't scope over the entire type, so the type variables it binds are considered local to the type. This is enabled by RankNTypes, which is included in QuantifiedConstraints.