6
votes

Why does this identity compile when I type it

f = (\x -> x) :: a -> a

but this one does not?

f x = x :: a -> a

When I just write

f x = x

And load it into ghci and type :t f I receive

f :: p -> p

So, shouldn't it be the same thing?

The error I receive is

Couldn't match expected type ‘a1 -> a1’ with actual type ‘p’ because type variable ‘a1’ would escape its scope This (rigid, skolem) type variable is bound by an expression type signature: forall a1. a1 -> a1

I already googled about the rigid, skolem thing and the error but it only gave me more questions.

Originally I wanted to write a function that takes two inputs and returns the first one, which only worked with the anonymous function. So I seem to lack some understanding when it comes to lambdas and typing. I am still at the beginning of learning Haskell.

f = (\x y -> x) :: a -> b -> a
1
The type annotation only applies to the RHS of the definition, not the entire definition.chepner

1 Answers

6
votes

You apply the type signature :: a -> a to x, not to f. You can add a type signature with:

f :: a -> a; f x = x

However, you can not specify that x is of type :: a anyway, since that a is a different type variable than the a in the outer type signature. You can enable the ScopedTypeVariables [ghc-doc] extension, to use type variables defined in an outer scope, like:

{-# LANGUAGE ScopedTypeVariables #-}

f :: forall a . a -> a
f x = x :: a