First, let us assume that local type inference is the sort of type inference found in Scala and C#. Scala local type inference is explained here: http://www.scala-lang.org/node/127
Also, let us assume, that a definition such as
fact 0 = 1
fact n = n * fact(n-1)
would count as local type inference — that is, type inference here is local to function fact. Scala does not permit such a type inferece; still let us count it as local.
The question, then, is whether anyone has a practical example of at least 2 mutually-recursive functions (or any other non-locality at your discretion) that derive some benefit from type inference? Please do not post silly examples such as:
odd 0 = false
odd n = even(n-1)
even 0 = true
even n = odd(n-1)
I suspect that non-silly, practical examples arise in parses. Also, please could you explain the benefits a programmer could derive from such uses of non-local type inference?
UPDATE:
I appreciate any example of insufficiency of local type inference and the need for full-blown type inference.
-
Your Haskell or OCaml example may be 90% correct, because you are only 90% understand the term “non-local type inference”. Still, you have to understand Haskell (or OCaml) type inference.
-
Your example may be written on Scala or C#. Please point out that compliler really has enough information to infer the type, but the type can not be inferred due to language specification or due to local-only nature of type inference in Scala or C#.
// And again, feel free to correct my english.
I’m not completely sure what examples would count for you, because you mention both non-locality and mutual recursion, and I don’t understand whether an example that exhibits just non-locality is enough.
I will say that a common technique in Haskell is to write functions whose return type is a class-constrained type variable not mentioned in the argument types. For example, like this:
In this case, the concrete type of the result of any call to
foois determined by type inference at the calling site. I.e., the return type of any call tofoois inferred from information not present in the definition offoo.One practical example of this is Haskell’s regular expression libraries. The interface uses this pattern so that, instead of having a bunch of different regexp matching functions that return different types, there is a regexp matching operator that is polymorphic on the return type as shown above, and thus the caller’s type inference controls what is returned.
So for example, if you do regexp matching in a calling context where the inferred return type is an integer, you get back number of matches. If the calling context expects a boolean, you get True if there were any matches. If the calling context expects a list of strings, you get a list of the substrings that matched the regexp. A bunch of other return type-specific behaviors are defined—and you can define your own for arbitrary return types by implementing your own instances of the library’s type class for results.