Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell and Rank-N polymorphism

Tags:

types

haskell

What's exactly wrong about the following hypothetical Haskell code? When I compile it in my brain, it should output "1".

foo :: forall a. forall b. forall c. (a -> b) -> c -> Integer -> b
foo f x n = if n > 0 then f True else f x

bar :: forall a. a -> Integer
bar x = 1

main = do
     putStrLn (show (foo bar 1 2))

GHC complains:

$ ghc -XRankNTypes -XScopedTypeVariables poly.hs 

poly.hs:2:28:
     Couldn't match expected type `a' against inferred type `Bool'
       `a' is a rigid type variable bound by
           the type signature for `foo' at poly.hs:1:14
     In the first argument of `f', namely `True'
     In the expression: f True
     In the expression: if n > 0 then f True else f x

poly.hs:2:40:
     Couldn't match expected type `Bool' against inferred type `c'
       `c' is a rigid type variable bound by
            the type signature for `foo' at poly.hs:1:34
     In the first argument of `f', namely `x'
     In the expression: f x
     In the expression: if n > 0 then f True else f x

What does that mean? Isn't it valid Rank-N polymorphism? (Disclaimer: I'm absolutely not a Haskell programmer, but OCaml doesn't support such explicit type signatures.)

like image 691
dcoffset Avatar asked Feb 20 '11 11:02

dcoffset


People also ask

What is arbitrary rank polymorphism in Haskell?

The GHC Users Guide has an Arbitrary Rank Polymorphism section. Normal Haskell '98 types are considered Rank-1 types. A Haskell '98 type signature such as implies that the type variables are universally quantified like so: forall can be floated out of the right-hand side of -> if it appears there, so:

What is rank-1 type in Haskell 98?

Normal Haskell '98 types are considered Rank-1 types. However, a forall appearing within the left-hand side of (->) cannot be moved up, and therefore forms another level or rank. The type is labeled "Rank-N" where N is the number of forall s which are nested and cannot be merged with a previous one.

Is Haskell a polymorphic language?

Haskell even allows class instances to be defined for types which are themselves polymorphic (either ad-hoc or parametrically). So for example, an instance can be defined of Eq that says "if a has an equality operation, then [a] has one".

What is a generic type in Haskell?

In Haskell, this means any type in which a type variable, denoted by a name in a type beginning with a lowercase letter, appears without constraints (i.e. does not appear to the left of a => ). In Java and some similar languages, generics (roughly speaking) fill this role.


1 Answers

You're not actually using rank-N polymorphism in your code.

foo :: forall a. forall b. forall c. (a -> b) -> c -> Integer -> b

This is an ordinary rank-1 type. It reads: forall a,b and c this function can take a function of type a -> b, a value of type c and an Integer and return a value of type b. So it says that it can take a function of type Bool -> Integer or a function of type Integer -> Integer. It does not say that the function has to be polymorphic in its argument. To say that, you need to use:

foo :: forall b. forall c. (forall a. a -> b) -> c -> Integer -> b

Now you're saying that the type of the function needs to be forall a. a -> b, where b is fixed, but a is a newly introduced variable, so the function needs to be polymorphic in its argument.

like image 183
sepp2k Avatar answered Sep 28 '22 06:09

sepp2k