Lennart mentioned this recently; the situation is as follows: 1. semi-unification (the general one) is undecidable 2. it is semi-decidable 3. the semi-decision procedure for semi-unification can be augmented with heuristics that finds almost all cases in which it fails (this is a kind of modified occur-check). It is a "well-behaving" undecidability. You can modify an ordinary (unification-based) type-inference algorithm as follows to get the more general types: when type-checking a recursive definition, say letrec f = ... f ..... f ... use a fresh type variable for every occurrence of f and proceed as usual. If for the remaining parts (the ...) the type-checking has succeeded, the algorithm inspects what happened to all those type variables for f, i.e. which types have been substituted for them. In a unification-based setting you had to unify them, here: you have to semi-unify them, i.e. suppose the types of those three occurrences are as follows letrec f = ... f ..... f ... t1 t2 t3 then we have to solve the semi-unification problem (notice the difference between using and defining occurrence) t1 > t2 t1 > t3 i.e. we have to find substitutions sigma, tau1, tau2, such that tau1(sigma(t1)) = sigma(t2) tau2(sigma(t1)) = sigma(t3) The type sigma(t1) is the type for our f, and we have to apply sigma throughout the range of our type-inference. One can enhance the performance of the algorithm by the usual Haskell/Miranda dependency analysis for letrecs (to be honest, I'm not sure that it is really an improvement -- the semi-unification algorithm does very similar things anyway), which basically reduces bigger semi-unification problems to smaller ones. Stefan Kahrs