F#编译器似乎以(相当)严格的从上到下,从左到右的方式执行类型推断.这意味着您必须执行诸如在使用之前放置所有定义,文件编译的顺序很重要,并且您倾向于需要重新排列内容(通过|>
或有什么)以避免使用显式类型注释.
如何使这更灵活,并且计划用于F#的未来版本有多难?显然它可以完成,因为Haskell(例如)没有这种限制同样强大的推理.F#的设计或意识形态是否有任何本质上的不同?
F#的设计或意识形态是否有任何本质上的不同?
是.F#使用名义而不是结构类型,因为它更简单,因此对于凡人来说更容易使用.
考虑这个F#示例:
let lengths (xss: _ [] []) = Array.map (fun xs -> xs.Length) xss let lengths (xss: _ [] []) = xss |> Array.map (fun xs -> xs.Length)
前者不能编译,因为xs
匿名函数内部的类型无法推断,因为F#不能表达"带有Length
成员的某个类"的类型.
相比之下,OCaml可以表达直接的等价物:
let lengths xss = Array.map (fun xs -> xs#length) xss
因为OCaml可以表达那种类型(它是写的
).请注意,这需要比F#或Haskell当前具有更强大的类型推断,例如OCaml可以推断和类型.
但是,已知此功能是可用性问题.例如,如果你搞砸了代码中的其他地方,那么编译器还没有推断出xs
应该是一个数组的类型,所以它可以提供的任何错误消息只能提供诸如"某种类型与长度成员"之类的信息而不是"数组".只有稍微复杂的代码,这很快就会失控,因为你有大量的类型,许多结构推断的成员不完全统一,导致不可理解的(类似C++/STL)错误消息.
关于"Haskell同样强大的推理",我不认为Haskell必须处理
OO风格的动态子类型(类型类可以做一些类似的东西,但类型类更容易输入/推断)
方法重载(类型类可以做一些类似的东西,但类型类更容易键入/推断)
也就是说,我认为F#必须处理Haskell没有的一些难题.(几乎可以肯定,Haskell必须处理F#没有的一些难题.)
正如其他答案所提到的,大多数主要的.NET语言都将Visual Studio工具作为主要的语言设计影响(参见例如LINQ如何"从...选择"而不是SQL-y"select ... from ",从程序前缀获取intellisense的动机.智能感知,错误曲线和错误信息可理解性都是F#设计的工具因素.
很可能做得更好并推断更多(不牺牲其他经验),但我不认为这是我们未来版本语言的重中之重.(Haskellers可能会看到F#类型推断有点弱,但它们可能超过C#,他们认为F#类型推断非常强大.:))
也许很难以非破坏的方式扩展类型推断; 可以在将来的版本中将非法程序更改为合法程序,但是您必须非常小心地确保以前合法的程序不会根据新的推理规则更改语义,并且可能会出现名称解析(每种语言都可怕的噩梦)以令人惊讶的方式与类型推断相互作用.
我认为F#使用的算法有一个好处,就是很容易(至少粗略地)解释它是如何工作的,所以一旦理解了它,你就可以对结果有一些期望.
该算法总是有一些限制.目前,很容易理解它们.对于更复杂的算法,这可能很困难.例如,我认为您可能会遇到这样的情况,即您认为算法应该能够推断出某些东西 - 但如果它足以覆盖整个案例,则它将是不可判定的(例如,可以永远保持循环).
另一个想法是从顶部到底部检查代码对应于我们如何读取代码(至少有时).所以,也许我们倾向于以支持类型推理的方式编写代码也可以使代码对人们更具可读性......
F#使用一次传递编译,这样您只能引用先前在您当前所在文件中定义的类型或函数,或者出现在编译顺序中先前指定的文件中.
我最近问Don Syme关于制作多个源代码来改进类型推断过程.他的答复是"是的,可以进行多次通过类型推断.还有单通道变量产生一组有限的约束.
然而,这些方法倾向于在可视化编辑器中提供错误的错误消息和较差的智能感知结果."
http://www.markhneedham.com/blog/2009/05/02/f-stuff-i-get-confused-about/#comment-16153
简短的回答是F#基于SML和OCaml的传统,而Haskell来自米兰达,Gofer等略有不同的世界.历史传统的差异是微妙的,但却是无处不在的.这种区别在其他现代语言中也是平行的,例如ML-like Coq与Haskell-like Agda具有相同的排序限制.
这种差异与懒惰与严格评估有关.宇宙的哈斯克尔方面相信懒惰,一旦你已经相信懒惰,那么在类型推理之类的事情上添加懒惰的想法是不费脑子的.在宇宙的ML方面,只要懒惰或相互递归是必要的,必须通过使用诸如with,and,rec之类的关键字来明确指出.我更喜欢Haskell方法,因为它导致较少的样板代码,但是很多人认为最好明确这些事情.