From OCaml to F# -> type inference
-
text/sourcefragment 5/1/2013 6:52:44 AM Claus Jespersen (cjesp) 1Wednesday, May 01, 2013 6:52 AM
Hi,
A couple of years ago, I wrote a compiler in OCaml for a very large subset of the Java programming language. I enjoyed using OCaml and IMO it is a perfect language for writing compilers in.
However, lately I have begun giving F# a go since it can be considered a successor to OCaml, and enjoys interop with the .NET platform. I have however found some errors that makes me wonder if the type inference system in F# is that much different. for instance:
let convertStrToIntArray (s:(int * string) list) = let rec convert input = //(input:(int * string) list) = match input with | (count, freqs) :: rest -> let freqsArr = freqs.Split ';' let freqsIntArr = Array.map (fun freq -> match Int32.TryParse freq with | (true, result) -> result | (false,_) -> -1) freqsArr (count, freqsIntArr) :: convert rest | [] -> [] convert s
The above code generates the following error at the freqs.Split function:
"Error 1 Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved."
how is that possible? If I hover over s in the last line where the recursive function it says (int * string) list as it's type. AFAIK OCaml would easily infer the right types in this circumstance.
However if I change the code to the following:
let convertStrToIntArray s = //(s:(int * string) list) = let rec convert (input:(int * string) list) = match input with | (count, freqs) :: rest -> let freqsArr = freqs.Split ';' let freqsIntArr = Array.map (fun freq -> match Int32.TryParse freq with | (true, result) -> result | (false,_) -> -1) freqsArr (count, freqsIntArr) :: convert rest | [] -> [] convert s
Such that the type (int * string) list is typed at the recursive part, then it does not generate any errors.
Why does one need to type the types directly in the recursive function, rather than in the outer function argument?
All Replies
-
text/html 5/1/2013 8:13:03 AM N0nam3 1Wednesday, May 01, 2013 8:13 AM
Hindley-Milner type inference in F# is quite complicated topic and it would be better to seek for fine-grained details from here .
But your case is quite easy: as type inference applies from the left to the right top down of your code the first chance for the compiler to deduce the complete signature of the inner convert function happens only at the last line of the snippet (convert s) where it would be known from the declaration of the outer function. Prior to this point it has no clue that the second tuple member freqs is of type string. As to Intellisense for this last line, it works because the outer function in the first snippet explicitly forward defines what argument s is.
As soon as in the second snippet you make a forward type prompt for the inner function compiler can easily deduce that Split is a method of string type.
- Edited by N0nam3 Wednesday, May 01, 2013 8:13 AM
- Edited by N0nam3 Wednesday, May 01, 2013 8:17 AM
- Edited by N0nam3 Wednesday, May 01, 2013 8:19 AM
- Edited by N0nam3 Wednesday, May 01, 2013 8:21 AM
- Marked As Answer by Claus Jespersen (cjesp) Wednesday, May 01, 2013 11:32 AM
-
text/html 5/1/2013 11:32:48 AM Claus Jespersen (cjesp) 0Wednesday, May 01, 2013 11:32 AM
Thanks for the reply N0nam3
I think I will give the F# specification a look when I get some time on my hands.