same function's type accepted in top level, but rejected in where clause

Hi all, I came across an interesting type checker error, a function is accepted in top level, but rejected by type checker when moved to `where ...` clause. I moved required code to a new module for demonstration purposes: module Bug where fix :: (a -> a) -> a fix f = let x = f x in x data Fix f = Fix (f (Fix f)) unFix :: Fix f -> f (Fix f) unFix (Fix a) = a data ListF a l = NilF | ConsF a l instance Functor (ListF a) where fmap _ NilF = NilF fmap f (ConsF a l) = ConsF a (f l) fold :: Functor f => (f a -> a) -> Fix f -> a fold f a = f (fmap (fold f) (unFix a {- f (Fix f) -})) unfold :: Functor f => (a -> f a) -> a -> Fix f unfold f a = Fix (fmap (unfold f) (f a)) Now, after this code, type checker accept this function: iterateListF :: (a -> a) -> a -> Fix (ListF a) iterateListF fn e = unfold (foldFn fn) e foldFn :: (a -> a) -> a -> ListF a a foldFn fn a = ConsF a (fn a) But rejects this: iterateListF :: (a -> a) -> a -> Fix (ListF a) iterateListF fn e = unfold f e where f :: a -> ListF a a f a = ConsF a (fn a) With error: bug.hs:27:20: Couldn't match expected type `a1' with actual type `a' `a1' is a rigid type variable bound by the type signature for f :: a1 -> ListF a1 a1 at bug.hs:26:10 `a' is a rigid type variable bound by the type signature for iterateListF :: (a -> a) -> a -> Fix (ListF a) at bug.hs:23:17 In the return type of a call of `fn' In the second argument of `ConsF', namely `(fn a)' In the expression: ConsF a (fn a) Changing type variables in type of `f` to `x` fails with this error: bug.hs:28:20: Couldn't match expected type `x' with actual type `a' `x' is a rigid type variable bound by the type signature for f :: x -> ListF x x at bug.hs:27:10 `a' is a rigid type variable bound by the type signature for iterateListF :: (a -> a) -> a -> Fix (ListF a) at bug.hs:24:17 In the return type of a call of `fn' In the second argument of `ConsF', namely `(fn a)' In the expression: ConsF a (fn a) Failed, modules loaded: none. .. and this is strange because error message describes function as it is before changing `a` to `x`. Any ideas why this definition rejected? Is this a bug in GHC? --- Ömer Sinan Ağacan http://osa1.net

If you remove the type signature from f in the where clause it will
work. The reason is because the type signature listed there, the a is
a different a than in the top level signature. If you change it from
a to x, it says it should be the a that you can't seem to specify.
If you add the pragma ScopedTypeVariables to your file, it works the
way you would assume. However you will have to change the toplevel
signature to iterateListF :: forall a. (a -> a) -> a -> Fix (ListF a)
in order to make it work (added the forall a.).
On Fri, Jul 5, 2013 at 4:35 PM, Ömer Sinan Ağacan
Hi all,
I came across an interesting type checker error, a function is accepted in top level, but rejected by type checker when moved to `where ...` clause.
I moved required code to a new module for demonstration purposes:
module Bug where
fix :: (a -> a) -> a fix f = let x = f x in x
data Fix f = Fix (f (Fix f))
unFix :: Fix f -> f (Fix f) unFix (Fix a) = a
data ListF a l = NilF | ConsF a l
instance Functor (ListF a) where fmap _ NilF = NilF fmap f (ConsF a l) = ConsF a (f l)
fold :: Functor f => (f a -> a) -> Fix f -> a fold f a = f (fmap (fold f) (unFix a {- f (Fix f) -}))
unfold :: Functor f => (a -> f a) -> a -> Fix f unfold f a = Fix (fmap (unfold f) (f a))
Now, after this code, type checker accept this function:
iterateListF :: (a -> a) -> a -> Fix (ListF a) iterateListF fn e = unfold (foldFn fn) e
foldFn :: (a -> a) -> a -> ListF a a foldFn fn a = ConsF a (fn a)
But rejects this:
iterateListF :: (a -> a) -> a -> Fix (ListF a) iterateListF fn e = unfold f e where f :: a -> ListF a a f a = ConsF a (fn a)
With error:
bug.hs:27:20: Couldn't match expected type `a1' with actual type `a' `a1' is a rigid type variable bound by the type signature for f :: a1 -> ListF a1 a1 at bug.hs:26:10 `a' is a rigid type variable bound by the type signature for iterateListF :: (a -> a) -> a -> Fix (ListF a) at bug.hs:23:17 In the return type of a call of `fn' In the second argument of `ConsF', namely `(fn a)' In the expression: ConsF a (fn a)
Changing type variables in type of `f` to `x` fails with this error:
bug.hs:28:20: Couldn't match expected type `x' with actual type `a' `x' is a rigid type variable bound by the type signature for f :: x -> ListF x x at bug.hs:27:10 `a' is a rigid type variable bound by the type signature for iterateListF :: (a -> a) -> a -> Fix (ListF a) at bug.hs:24:17 In the return type of a call of `fn' In the second argument of `ConsF', namely `(fn a)' In the expression: ConsF a (fn a) Failed, modules loaded: none.
.. and this is strange because error message describes function as it is before changing `a` to `x`.
Any ideas why this definition rejected? Is this a bug in GHC?
--- Ömer Sinan Ağacan http://osa1.net
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

If you add the pragma ScopedTypeVariables to your file, it works the way you would assume. However you will have to change the toplevel signature to iterateListF :: forall a. (a -> a) -> a -> Fix (ListF a) in order to make it work (added the forall a.).
Thanks, that worked. As far as I understand, the problem is because in this definition: where f :: a -> ListF a a f a = ConsF a (fn a) There's an implicit quantifier in type of `f`, like this: `f :: forall a. a -> ListF a a`. When I add `ScopedTypeVariables` and `forall a. ...` in top level definition, it's like all `a`s in scope of top level definition are same, except when explicitly defined as `forall a. ...`. Is my intuition correct? --- Ömer Sinan Ağacan http://osa1.net

On Fri, Jul 5, 2013 at 11:03 PM, Ömer Sinan Ağacan
There's an implicit quantifier in type of `f`, like this: `f :: forall a. a -> ListF a a`. When I add `ScopedTypeVariables` and `forall a. ...` in top level definition, it's like all `a`s in scope of top level definition are same, except when explicitly defined as `forall a. ...`.
Is my intuition correct?
Yes it is ! :) ScopedTypeVariables is a very nice and non problematic extension, it may even be made part of some future Haskell standard. -- Jedaï

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 08/07/13 19:50, Chaddaï Fouché wrote:
On Fri, Jul 5, 2013 at 11:03 PM, Ömer Sinan A?acan
wrote: There's an implicit quantifier in type of `f`, like this: `f :: forall a. a -> ListF a a`. When I add `ScopedTypeVariables` and `forall a. ...` in top level definition, it's like all `a`s in scope of top level definition are same, except when explicitly defined as `forall a. ...`.
Is my intuition correct?
Yes it is ! :) ScopedTypeVariables is a very nice and non problematic extension, it may even be made part of some future Haskell standard.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Is this just speculation and wishful thinking or has there actually been discussion about it already? I think it'd be great if it was the part of the standard but I'm sure there are tens of naysayers ready to repaint my shed. - -- Mateusz K. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.20 (GNU/Linux) iQIcBAEBAgAGBQJR2wu9AAoJEM1mucMq2pqXM64P/RGQR+/qItSQumuUCXkagp5V jMx3UaoJIyjOlcDBAmbHitZH4gTSNKFh3toWH7brb8SPfMpzgl1rGFtCsr4pzvOS 3GzM2giTvw9cs8rGv5f1O7h2hSpaNgU9xVxzpYxRd4g/h3sMEuWji++jJDhDY6mo SkOmtMGozi4AwhtMrybDjeNhsno82mKPU9SQF8fKz1yj/MMJY9BwWGs6k3OlvxWM eNqyRfoyQtgRLB2Th1dJqIV30dakmnMSCX9ALnD0Pg8/lQnqj0iJ1O7b1S2iqn/e UtxTTyOgwNF56K4CnUpt/os//bHyqsQFFQyFBkdZMstcro57Ta7wcXcPqzhuySNQ GOerfMkVAOApVkXO6t78XLgy1vkc+RXaxY5obICXN+nRu4WuZBLow0HdxlkKffHE cwXHigU3KkKIeoyvgpI9pEFSUMPJcBvI7SG9MqWIb5sOxuZhFv2KmDSanptL1bA8 yccRb0yN2vfmL3+hLIBKTfn9TWKCpnEaCpwPBCCM9kFvA31D0Rul5EZT5H8IB2/9 t5DGTOXlACgKbr8GODCFdtLQUCXaKYj7N83yQHt9kBC6PfVe9ECOJjnZrfvnA1na sTPzzxNFWdAmKQBhZBlldwYvLNtIO7UK0H+l01gacKd5KOldS6u1K+5EDT0WuIg5 LPxtoY8kYIJlwUmZgAqZ =ZaDI -----END PGP SIGNATURE-----
participants (4)
-
Chaddaï Fouché
-
David McBride
-
Mateusz Kowalczyk
-
Ömer Sinan Ağacan