具有类型注释的List.reduce部分应用程序给出错误FS0030

时间:2016-07-05 21:13:13

标签: f#

let ones = List.map (fun _ -> 1)

无法推广并提供FS0030 value error.

这可以通过类型注释修复(以及其他方式):

let ones<'a> : 'a list -> int list = List.map (fun _ -> 1)

但是在以下情况下:

let count = List.fold (fun t _ -> t + 1) 0

什么类型的注释可以使用,或者,为什么不添加类型注释有助于编译器?

let count : 'a list -> int = List.fold (fun t _ -> t + 1) 0

(我知道List.length,或者我可以使用count x = x |&gt; List.fold等等,我试图理解的是为什么类型注释适用于List .map示例,但不是List.reduce)

2 个答案:

答案 0 :(得分:4)

简短回答

这是正确的语法:

let count<'a> : 'a list -> int = List.fold (fun t _ -> t + 1) 0

说明

它不是有用的类型注释,它是通用参数 这将编译(甚至工作,种类):

let count<'a> = List.fold (fun t _ -> t + 1) 0

错误FS0030与编译器无法确定类型有关。它是关于你声明一个类型(而不是函数)的类型,它的类型是通用的。由于此处描述的原因太复杂,因此不允许使用此类值。或者,更准确地说,它们是允许的,但前提是您已通过明确指定通用参数表明您知道自己在做什么。

但是,即使使用泛型参数,值的实际推断类型也可能不是您所期望的。例如,如果您将上述示例粘贴到F#代码编辑器中并悬停在count上,您会发现其类型为obj list -> int

奇怪?这里甚至更奇怪 - 在定义之后添加另一行:

let count<'a> = List.fold (fun t _ -> t + 1) 0
let c = count [1..5]

现在将鼠标悬停在count上 - 其类型变为int list -> int

奇怪?这里更加陌生: - )

let count<'a> = List.fold (fun t _ -> t + 1) 0
let c = count [1..5]
let c2 = count ["a"; "b"; "c"]

现在第三行根本没有编译,抱怨&#34; a&#34;,&#34; b&#34;和&#34; c&#34;预计为int

WTF?
这是F#的一个特点 - 推断&#34;临时&#34;最常见的类型,然后根据实际使用情况进行修复。这就是隔离count成为obj list -> intobj是最终超类型)的原因,但只要您将其与int list一起使用,编译器就会修复改为int list -> int的类型。如果在此之后尝试将其与string list一起使用,那么可以理解的是不能编译。

人们可以用多态算术运算符观察到相同的效果:

let add x y = x + y
add 2.0 4.5
add "a" "b"

隔离的第一行指的是int -> int -> int,但只要添加第二行,add的类型就会变为float -> float -> float(根据使用情况),然后是第三行线路可以理解失败。

可以通过指定所需的确切类型来修复此情况:

let count<'a> : 'a list -> int = List.fold (fun t _ -> t + 1) 0

现在count将是一个真正的通用函数。

答案 1 :(得分:3)

let count<'a> : 'a list -> int = List.fold (fun t _ -> t + 1) 0