为什么Console.WriteLine无法确定我的类型?在F#中

时间:2013-10-06 22:24:50

标签: types f# function-composition

这是我的代码:

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

我想熟悉函数组合运算符的工作方式,但由于某些原因,F#无法找到函数的最佳重载...

在我明确说明参数的示例中,它将类型设置为val print : x:('a * int) list -> unit,因此我使用组合运算符<<在函数中显式设置类型,希望我得到正确的结果......我没有......

然后我用函数something创建了一个显式声明的参数类型,只是为了查看它返回的内容......它返回:val something : x:(string * int) list -> string list

所以它肯定会返回一个类型...一个字符串列表,我知道Console.WriteLine能够打印...那么为什么它告诉我它无法确定过载?

1 个答案:

答案 0 :(得分:4)

F#中的类型推断从左到右工作 - 这意味着编译器使用程序中早期可用的信息来确定程序中稍后的表达式类型(这是一个小小的简化,但它是一般的想法)。

所以在你的代码中,当你写:

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

..编译器不会通过List.map调用将有关函数输入类型的信息传播回WriteLine调用。这也解释了为什么正向链接和组合通常在F#中更有用。以下作品:

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

要使原始代码正常工作,您可以提供一些最少量的信息,以确定正确的WriteLine重载是object的重载。如果你告诉编译器需要列出某个东西,那么它可以选择正确的重载:

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