F#编译器似乎以(相当)严格的从上到下,从左到右的方式执行类型推断。这意味着您必须做一些事情,例如将所有定义放到使用之前,文件编译的顺序很重要,并且您往往需要重新整理内容(通过|>
或通过您拥有的东西),以避免使用显式的类型注释。
使它更加灵活有多难,并且计划在F#的未来版本中使用它吗?显然,这是可以做到的,因为Haskell(例如)在推理能力相当强的情况下没有这种限制。导致此问题的F#的设计或意识形态与生俱来有什么不同?
F#编译器似乎以(相当)严格的从上到下,从左到右的方式执行类型推断。这意味着您必须做一些事情,例如将所有定义放到使用之前,文件编译的顺序很重要,并且您往往需要重新整理内容(通过|>
或通过您拥有的东西),以避免使用显式的类型注释。
使它更加灵活有多难,并且计划在F#的未来版本中使用它吗?显然,这是可以做到的,因为Haskell(例如)在推理能力相当强的情况下没有这种限制。导致此问题的F#的设计或意识形态与生俱来有什么不同?
floor
函数的运行速度通常比任何其他编译语言都要慢几个数量级,这恰恰是因为Haskell函数无法推断正确的静态类型,因此只能求助于运行时分派。另外,如果我停止从randIntList
这里具有的函数中删除顶级类型注释,则它将停止编译并显示臭名昭著的ambiguous type variable
错误。
Answers:
关于“ Haskell同样强大的推论”,我认为Haskell不必处理
也就是说,我认为F#必须处理Haskell不需要的一些困难的工作。(几乎可以肯定,Haskell必须处理F#不能处理的一些难题。)
正如其他答案所提到的那样,大多数主要的.NET语言都将Visual Studio工具作为主要的语言设计影响力(请参见例如LINQ如何具有“ from ... select”而不是SQL-y“ select ... from”)。 ”,其动机是从程序前缀获取智能感知。Intellisense,错误信息和错误消息的可理解性都是通知F#设计的工具因素。
可能有可能做得更好,推断更多(不牺牲其他经验),但是我认为这不是该语言未来版本的高度优先事项。(Haskeller族人可能认为F#类型推断有些弱,但是可能比那些认为F#类型推断非常强的C#人数要多。:))
以不间断的方式扩展类型推断可能也很困难。在将来的版本中将非法程序更改为合法程序是可以的,但是您必须非常小心以确保以前的合法程序在新的推理规则下不会更改语义,并且名称解析(每种语言的噩梦)很可能以令人惊讶的方式与类型推断更改进行交互。
导致此问题的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可以表示该类型(已写入<length: 'a ..>
)。注意,这需要比F#或Haskell当前具有更强大的类型推断,例如OCaml可以推断和类型。
但是,已知此功能是可用性问题。例如,如果您在代码中的其他地方搞砸了,则编译器尚未推断出该类型xs
应该是数组,因此它可以给出的任何错误消息只能提供诸如“某些类型带有Length成员”的信息,而不能“数组”。仅使用稍微复杂一些的代码,当您有大量类型且许多结构推断成员并没有统一在一起时,这很快就失去了控制,从而导致了令人费解的(类似于C ++ / STL的)错误消息。
System.Windows.Controls.ScrollBarVisibility.Visible
,.NET上Visible
的OCaml就是这样)。我中的企业家更喜欢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来自Miranda,Gofer等稍有不同的世界。历史传统的差异是微妙的,但却是普遍的。这种区别在其他现代语言中也是类似的,例如具有相同排序限制的类似ML的Coq与没有类似Haskell的Agda一样。
这种差异与延迟评估和严格评估有关。宇宙的Haskell一方相信惰性,一旦您已经相信惰性,将懒惰添加到类型推断之类的想法就变得轻而易举了。在Universe的ML端,每当需要懒惰或相互递归时,必须使用诸如和,和,rec等之类的关键字来明确指出。许多人认为最好将这些内容明确化。