Reputation: 4219
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?
Upvotes: 4
Views: 95
Reputation: 27013
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
.
Upvotes: 6