为什么F#的types推断如此变幻莫测?

F#编译器似乎以(相当)严格的从上到下,从左到右的方式执行types推断。 这意味着你必须做一些事情,比如把所有的定义放在使用之前,文件编译的顺序是非常重要的,而你往往需要重新排列一些东西(通过|>或者你有什么)来避免显式的types注释。

如何使这个更加灵活,并且计划将来的F#版本呢? 显然这是可以做到的,因为Haskell(例如)对同样强大的推理没有这样的限制。 F#的devise或意识形态有什么本质上的不同吗?

关于“Haskell同样强大的推论”,我不认为Haskell必须处理

  • OO风格的dynamic子types(types类可以做一些类似的东西,但types类更容易input/推断)
  • 方法重载(types类可以做一些类似的东西,但types类更容易键入/推断)

也就是说,我认为F#必须处理一些Haskell没有的难题。 (几乎可以肯定的是,Haskell必须处理一些F#没有的难题。)

正如其他答案所提到的,大多数主要的.NET语言都将Visual Studio工具作为一种主要的语言devise影响力(参见例如LINQ如何“从… select”而不是从SQL-y“select … from “,从一个程序前缀获得intellisense的动机)。 智能感知,错误波形和错误消息可理解性都是通知F#devise的工具因素。

可能做得更好,推断更多(不牺牲其他经验),但我认为这不是我们未来版本语言的重中之重。 (Haskellers可能会认为F#types推断有点弱,但可能被那些认为F#types推断非常强大的C#人员超过)

以非破坏性的方式扩展types推断也可能是困难的; 在将来的版本中将非法程序转换为合法程序也是可以的,但是必须非常小心,以确保以前合法的程序不会根据新的推理规则改变语义,并且名称parsing(每种语言中的可怕噩梦)以惊人的方式与types推理相互作用。

F#的devise或意识形态有什么本质上的不同吗?

是。 F#使用名义式而不是结构式打字,因为它比较简单,因此对于凡人来说更容易使用。

考虑这个F#的例子:

 let lengths (xss: _ [] []) = Array.map (fun xs -> xs.Length) xss let lengths (xss: _ [] []) = xss |> Array.map (fun xs -> xs.Length) 

前者不编译,因为匿名函数内部的xstypes不能被推断,因为F#不能表示types“有Length成员的某个类”。

相反,OCaml可以expression直接的等价物:

 let lengths xss = Array.map (fun xs -> xs#length) xss 

因为OCaml可以表示这种types(它写成<length: 'a ..> )。 请注意,这需要比F#或Haskell目前有更强大的types推断,例如OCaml可以推断和types。

但是,此function被称为可用性问题。 例如,如果你在代码的其他地方搞错了,那么编译器还没有推断出xs的types应该是一个数组,所以它给出的任何错误信息都只能提供“某种types的长度成员”和不是“arrays”。 由于只有稍微复杂的代码,这很快失去控制,因为你有大量的结构推断成员,并不完全统一,导致不可理解的(类似于C ++ / STL的)错误消息的大量types。

我认为F#使用的algorithm有一个好处,就是它很容易(至less粗略地)解释它是如何工作的,所以一旦理解了它,就可以对结果有一些期望。

algorithm总会有一些限制。 目前,它们很容易理解。 对于更复杂的algorithm,这可能是困难的。 例如,我认为你可能会遇到这样的情况,你认为algorithm应该能够推断出某些东西 – 但是如果它足以覆盖整个案例,它将是不可判定的(例如可以永久循环)。

另一个想法是从上到下检查代码对应于我们如何阅读代码(至less有时)。 所以, 也许我们倾向于使用types推断的方式来编写代码,这也使得代码对于人们更具可读性。

F#使用一次编译,因此只能引用在当前文件中较早定义的types或函数,或者在编译顺序前面指定的文件中出现。

我最近要求Don Syme提供多个源代码通行证来改进types推断过程。 他的回答是“是的,有可能做多通道types推断。还有单通变化,产生有限的一组约束。

然而,这些方法往往会给糟糕的错误信息和可视化编辑器中的弱智能结果。“

http://www.markhneedham.com/blog/2009/05/02/f-stuff-i-get-confused-about/#comment-16153

简而言之,F#是基于SML和OCaml的传统,而Haskell则来自Miranda,Gofer等稍微不同的世界。 历史传统的差异是微妙的,但普遍。 这种区分在其他现代语言中也是并行的,比如类似ML的Coq,与Haskell类似的Agda有相同的sorting限制。

这种差异与懒惰vs严格评估有关。 宇宙的哈斯克尔一面相信懒惰,一旦你已经相信懒惰,那么把类似推理的东西join懒惰的想法是不容易的。 而在宇宙的ML方面,每当懒惰或相互recursion是必要的,必须明确地指出使用关键字,如 rec等。我更喜欢Haskell方法,因为它导致较less的样板代码,但有很多人认为将这些事情明确expression出来会更好。