Why can't the type of id be specialised to (forall a. a -> a) -> (forall b. b -> b)?

前端 未结 3 2040
一向
一向 2021-02-01 16:21

Take the humble identity function in Haskell,

id :: forall a. a -> a

Given that Haskell supposedly supports impredicative polymorphism, it

3条回答
  •  后悔当初
    2021-02-01 16:50

    I'm not an expert on impredictive types, so this is at once a potential answer and a try at learning something from comments.

    It doesn't make sense to specialize

    \/ a . a -> a                       (1)
    

    to

    (\/ a . a -> a) -> (\/ b . b -> b)  (2)
    

    and I don't think impredictive types are a reason to allow it. The quantifiers have the effect of making the types represented by the left and right side of (2) inequivalent sets in general. Yet the a -> a in (1) implies left and right side are equivalent sets.

    E.g. you can concretize (2) to (int -> int) -> (string -> string). But by any system I know this is not a type represented by (1).

    The error message looks like it results from an attempt by the Haskel type inferencer to unify the type of id

    \/ a . a -> a
    

    with the type you've given

    \/ c . (c -> c) -> \/ d . (d -> d)
    

    Here I'm uniqifying quantified variables for clarity.

    The job of the type inferencer is to find a most general assignment for a, c, and d that causes the two expressions to be syntactically equal. It ultimately finds that it's required to unify c and d. Since they're separately quantified, it's at a dead end and quits.

    You are perhaps asking the question because the basic type inferencer -- with an ascription (c -> c) -> (d -> d) -- would just plow ahead and set c == d. The resulting type would be

    (c -> c) -> (c -> c)
    

    which is just shorthand for

    \/c . (c -> c) -> (c -> c)
    

    This is provably the least most general type (type theoretic least upper bound) expression for the type of x = x where x is constrained to be a function with the same domain and co-domain.

    The type of "restricedId" as given is in a real sense excessively general. While it can never lead to a runtime type error, there are many types described by the expression you've given it - like the aforementioned (int -> int) -> (string -> string) - that are impossible operationally even though your type would allow them.

提交回复
热议问题