RankNTypes and scope of `forall'

后端 未结 2 1993
梦毁少年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条回答
  •  -上瘾入骨i
    2021-02-13 21:01

    f is just an ordinary polymorphic Haskell98 function, except the forall is written out explicitly. So all the type variables in the signature are parameters the caller gets to choose (without any constraints); in your case it's resolved a ~ ().

    g OTOH has a rank-2 type. It requires that its argument has the polymorphic type forall a . a. () does not have such a type, it is monomorphic. But undefined has this type (in fact, only undefined, and error etc.), if we add the explicit forall again.

    Perhaps it becomes clearer with a less trivial Rank2 function:

    h :: (forall a . (Show a, Num a) => a) -> String
    h a = show a1 ++ " :: Double\n"
         ++ show a2 ++ " :: Int"
     where a1 :: Double; a2 :: Int
           a1 = a; a2 = a
    

    GHCi> putStrLn $ h 4
    4.0 :: Double
    4 :: Int

    but I can't do

    GHCi> putStrLn $ h (4 :: Integer)

    <‌interactive>:4:15:
        Could not deduce (a ~ Integer)
        from the context (Show a, Num a)
          bound by a type expected by the context: (Show a, Num a) => a
          at <‌interactive>:4:12-27
          `a' is a rigid type variable bound by
              a type expected by the context: (Show a, Num a) => a
              at <‌interactive>:4:12
        In the first argument of `h', namely `(4 :: Integer)'
        In the second argument of `($)', namely `h (4 :: Integer)'
        In the expression: putStrLn $ h (4 :: Integer)

提交回复
热议问题