From the book by Tomas Petricek the following code doesn't work as compiler is unable to infer the type of the dt parameter:
> Option.map (fun dt -> dt.Year) (Some(DateTime.Now));;
error FS0072: Lookup on object of indeterminate type.
And if we specify type explicitly everything works fine:
> Option.map (fun (dt:DateTime) -> dt.Year) (Some(DateTime.Now));;
val it : int option = Some(2008)
Or we can use pipelining operator to "help" compiler to infer type:
> Some(DateTime.Now) |> Option.map (fun dt -> dt.Year);;
val it : int option = Some(2008)
The question is why F# compiler can't infer the type of the dt parameter? In this particular case it looks quite easy to infer the dt's type.
The logic behind it can be the following:
- the signature of
Option.mapismap : ('T -> 'U) -> 'T option -> 'U option - the type of the last parameter is
DateTime option - so our
mapusage looks likemap : ('T -> 'U) -> 'DateTime option -> 'U option - the compiler then can try to substitute
DateTimeas'Tto see if it would be correct, so we have(DateTime -> 'U) -> 'DateTime option -> 'U option - then it can infer the
'Utype by looking at the body of the lambda-function, so the'Ubecomesint - and we finally have
(DateTime -> int) -> 'DateTime option -> 'int option
So why F# can't do this inference? Tomas mentions in his book that F# infers types by going from the first to the last argument and that's why the order of arguments matters. And that's why F# can't infer the types in the first example. But why F# can't behave like C#, i.e. try to infer types incrementally starting with what is known?
In most cases F# is much more powerful when speaking about type inference... that't why I'm confused a bit.