RankNTypes and scope of `forall'

后端 未结 2 2035
梦毁少年i
梦毁少年i 2021-02-13 20:15

What is the difference between these?

{-# LANGUAGE RankNTypes #-}

f :: forall a. a -> Int
f _ = 1

g :: (forall a. a) -> Int
g _ = 1

In

2条回答
  •  天命终不由人
    2021-02-13 21:05

    Think of forall as an anonymous type function. All data types in Haskell which have type variables in their type signature implicitly have a forall. For example consider:

    f :: a -> Int
    f _ = 1
    

    The above function f takes an argument of any type and returns an Int. Where does the a come from? It comes from the forall quantifier. Hence it's equivalent to:

    f :: (forall a . a -> Int)
    f _ = 1
    

    The forall quatifier can be used for any data type, not just functions. For example consider the types of the following values:

    () :: ()
    10 :: Int
    pi :: Floating a => a
    

    Here () and 10 are monomorphic (i.e. they can only be of one concrete type). On the other hand pi is polymorphic with a typeclass constraint (i.e. it can be of any type as long as that type is a instance of Floating). The type of pi written out explicitly is:

    pi :: (forall a . Floating a => a)
    

    Again the forall quantifier acts like a type function. It provides you the type variable a. Now consider the type of function g:

    g :: (forall a . a) -> Int
    g _ = 1
    

    Here g expects an argument of type forall a . a and returns an Int. This is the reason g () doesn't work: () is of type (), not of type forall a . a. In fact the only value of type forall a . a is undefined:

    undefined :: a
    

    Written out explicitly with forall:

    undefined :: (forall a . a)
    

    If you noticed I've always put parentheses around the forall quantifications. The reason I did this is to show you that when you use a forall quantification on a function the quantification extends all the way to the right. This is just like a lambda: if you don't put parentheses around the lambda Haskell will extend the lambda function all the way to the right. Hence the type of f is (forall a . a -> Int) and not (forall a . a) -> Int.

    Remember in the first case Haskell expects the type of the argument to be a (i.e. anything). However in the second case Haskell expects the type of the argument to be (forall a . a) (i.e. undefined). Of course if you try to evaluate undefined then your program will immediately halt with an error. Fortunately you're not trying to evaluate it.

提交回复
热议问题