I'm a beginner(ish) in Haskell and I find error message really hard to understand (I guess it comes with time). Anyway, to help me understanding my mistakes, I tried to add intermediate variable with type annotation in a let binding and found that it generate even more errors, even though my type are (I think) correct.
Example;
f :: a -> a f x = let x' = x :: a in x'
Generate the following error
test.hs:3:12: Couldn't match expected type `a2' with actual type `a' `a2' is a rigid type variable bound by an expression type signature: a2 at test.hs:3:12 `a' is a rigid type variable bound by the type signature for f :: a -> a at test.hs:1:6 In the expression: x :: a In an equation for x': x' = x :: a In the expression: let x' = x :: a in x
Am I doing something wrong or is it not possible to do so ?
You need the ScopedTypeVariables
extension for this to work, like this:
{-# LANGUAGE ScopedTypeVariables #-} f :: forall a. a -> a f x = let x' = x :: a in x'
If you have a type signature like this
f :: a -> a
then it indicates that f
is polymorphic and works for any choice of a
. So f
could be used at type Int -> Int
, or at type Bool -> Bool
, or at type [Int -> Bool] -> [Int -> Bool]
– whatever you like.
If you have a type annotation like this
x :: a
it means a similar thing, namely that x
should be usable at any type of your choice. But that's not true in your case. The outer function f
is polymorphic, but within the function, x
has to be of the same type a
that the user has chosen for the outer x
. By default, Haskell makes no connection between type variables occurring in different type signatures and annotations. However, you can tell it to do so by enabling the ScopedTypeVariables
extension. Now, by prefixing a -> a
with forall a.
, you can explicitly instruct Haskell to make a
visible as a specific type variable within the definition of f
. If you then annotate x :: a
, it refers to the outer a
rather than a new polymorphic a
.
For anyone who is looking to type annotate the binding instead of the expression - ScopedTypeVariables
allows you to do that too!
f1 = do let x :: Int = 5 y :: Int <- someMonadicOperation return $ x + y
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With