I have a problem with Haskell's scoping in where
definitions. When I have the following function f
, where I want to pass the x
to the locally defined function f1
without explicitely using it as a parameter, I get an error saying that the type of x
is incompatible with the one in the output of f1
, although it should be the same:
f :: Eq a => a -> [a] f x = f1 x where f1 :: Eq a => a -> [a] f1 y = [ x, y ]
The error is the following:
Couldn't match expected type `a1' against inferred type `a' `a1' is a rigid type variable bound by the type signature for `f1' at test.hs:4:11 `a' is a rigid type variable bound by the type signature for `f' at test.hs:1:8 In the expression: x In the expression: [x, y] In the definition of `f1': f1 y = [x, y] Failed, modules loaded: none.
When I however pass the x
as an additional parameter, as I did in the following code with the function g
, it works fine:
g :: Eq a => a -> [a] g x = g1 x x where g1 :: Eq a => a -> a -> [a] g1 x y = [ x, y ]
Is there a way to make the type a
in f
compatible to the type a
(or a1
) in f1
?
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.