Haskell scoping in nested function definitions using where

Dave is right above. Another way to think of it is that even though both of your type signatures refer to the variable a, it's not actually the same type variable. In the Haskell-prime notation, both signatures can be more explicitly written as:

forall a . Eq a => a -> [a]

meaning that for both functions, they can accept an argument of any type whatsoever (within Eq). This is obviously not the case here. In standard Haskell 98, the only option is to forgo the type signature for f1. But GHC (and others?) support lexically scoped type variables. So you could write

{-# LANGUAGE ScopedTypeVariables #-}

f :: forall a. Eq a => a -> [a]
f x = f1 x
    where
        f1 :: a -> [a]
        f1 y = [ x, y ]

and that would work fine.


The problem with your code is the locally scoped f1 type signature. It specifies that f1 can take any type

f1 :: Eq a => a -> [a]

Even though this is a local function, you've generalized this function to be able to take a type that won't exist within f, whatever this function receives HAS to come from f, so the type signature is unnecessary.

Just remove the f1 type signature.

Edit: Read my post back to myself, it's a bit unclear. a in f1 is a parameterized type that can take anything, but the arguments passed to it are already bound in f. So this function can only receive what its parent function receives, the type signature you're giving it breaks that rule. Hope that's a little more clear.