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)
答案 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 -> int
(obj
是最终超类型)的原因,但只要您将其与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