Search code examples
haskellpolymorphismparametric-polymorphismhindley-milner

Can I verify whether a given function type signature has a potential implementation?


In case of explicit type annotations Haskell checks whether the inferred type is at least as polymorphic as its signature, or in other words, whether the inferred type is a subtype of the explicit one. Hence, the following functions are ill-typed:

foo :: a -> b
foo x = x

bar :: (a -> b) -> a -> c
bar f x = f x

In my scenario, however, I only have a function signature and need to verify, whether it is "inhabited" by a potential implementation - hopefully, this explanation makes sense at all!

Due to the parametricity property I'd assume that for both foo and bar there don't exist an implementation and consequently, both should be rejected. But I don't know how to conclude this programmatically.

Goal is to sort out all or at least a subset of invalid type signatures like ones above. I am grateful for every hint.


Solution

  • Goal is to sort out all or at least a subset of invalid type signatures like ones above. I am grateful for every hint.

    You might want to have a look at the Curry-Howard correspondence.

    Basically, types in functional programs correspond to logical formulas. Just replace -> with implication, (,) with conjunction (AND), and Either with disjunction (OR). Inhabited types are exactly those having a corresponding formula which is a tautology in intuitionistic logic.

    There are algorithms which can decide provability in intuitionistic logic (e.g. exploiting cut-elimination in Gentzen's sequents), but the problem is PSPACE-complete, so in general we can't work with very large types. For medium-sized types, though, the cut-elimination algorithm works fine.

    If you only want a subset of not-inhabited types, you can restrict to those having a corresponding formula which is NOT a tautology in classical logic. This is correct, since intuitionistic tautologies are also classical ones. Checking whether a formula P is not a classical tautology can be done by asking whether not P is a satisfiable formula. So, the problem is in NP. Not much, but better than PSPACE-complete.

    For instance, both the above-mentioned types

    a -> b
    (a -> b) -> a -> c
    

    are clearly NOT tautologies! Hence they are not inhabited.

    Finally, note that in Haskell undefined :: T and let x = x in x :: T for any type T, so technically every type is inhabited. Once one restricts to terminating programs which are free from runtime errors, we get a more meaningful notion of "inhabited", which is the one addressed by the Curry-Howard correspondence.