Question

Here's my code:

open System

let places = [ ("Grandchester", 552);
               ("Cambridge", 117900);
               ("Prague", 1188126); ]

let statusByPopulation = function
                            | n when n > 1000000 -> "City"
                            | n when n > 50000   -> "Town"
                            | _                  -> "Village"

System.Console.WriteLine ( places |> List.map (fun (_, population) -> statusByPopulation population)) 

let print x = 
    Console.WriteLine (List.map (fun (_, population) -> statusByPopulation population) x) // what I'm trying to do

let something (x:(string * int) list) = 
    List.map (fun (_, population) -> statusByPopulation population) x; // checking what kinf of type it returns

let print: (string * int) list -> unit = 
    Console.WriteLine << List.map (fun (_, population) -> statusByPopulation population) // what I'm not allowed to do

System.Console.ReadKey () |> ignore

I wanted to get familiar with the way the function composition operator worked, but for some reason F# can't find the best possible overload for the function...

In the example where I explicitly state the parameter, it sets the type to be val print : x:('a * int) list -> unit, so I explicitly set the type in the function with the composition operator << hoping I'd get the correct result... I didn't...

I then made the function something with an explicitly declared type for the parameter, just to see what it'd return... It returns this: val something : x:(string * int) list -> string list

So it most definitely returns a type... a list of strings, which I know Console.WriteLine is capable of printing... So why does it tell me it can't determine the overload?

Was it helpful?

Solution

The type inference in F# works from the left to the right - this means that the compiler uses information available earlier in the program to determine types of expressions later in the program (this is a slight simplification, but it is the general idea).

So in your code, when you write:

Console.WriteLine << List.map (fun (_, population) -> statusByPopulation population)

.. the compiler does not propagate the information about the type of function input through the List.map call back to the WriteLine call. This also explains why forward chaining and composition are generally more useful in F#. The following works:

List.map (fun (_, population) -> statusByPopulation population) >> Console.WriteLine

To get your original code working, you could provide some minimal amount of information that is needed to determine that the right WriteLine overload is the one taking object. If you tell the compiler that it needs to take a list of something, then it can choose the right overload:

(Console.WriteLine:list<_> -> unit) << List.map (fun (_, population) -> 
    statusByPopulation population) 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top