当前位置:  开发笔记 > 编程语言 > 正文

为什么F#的类型推断如此变幻无常?

如何解决《为什么F#的类型推断如此变幻无常?》经验,为你挑选了5个好方法。

F#编译器似乎以(相当)严格的从上到下,从左到右的方式执行类型推断.这意味着您必须执行诸如在使用之前放置所有定义,文件编译的顺序很重要,并且您倾向于需要重新排列内容(通过|>或有什么)以避免使用显式类型注释.

如何使这更灵活,并且计划用于F#的未来版本有多难?显然它可以完成,因为Haskell(例如)没有这种限制同样强大的推理.F#的设计或意识形态是否有任何本质上的不同?



1> Jon Harrop..:

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)错误消息.


我的学者更喜欢OCaml方式,因为它可以更简洁(例如,.NET上的`System.Windows.Controls.ScrollBarVisibility.Visible`在OCaml中只是'可见').我的企业家更喜欢F#方式,因为对我的客户来说,易用性对于商业可行性至关重要.也许有更好的折衷方案.
有趣.考虑到所有事情,你更喜欢F#的名义打字还是OCaml的结构打字?

2> Brian..:

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

OO风格的动态子类型(类型类可以做一些类似的东西,但类型类更容易输入/推断)

方法重载(类型类可以做一些类似的东西,但类型类更容易键入/推断)

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

正如其他答案所提到的,大多数主要的.NET语言都将Visual Studio工具作为主要的语言设计影响(参见例如LINQ如何"从...选择"而不是SQL-y"select ... from ",从程序前缀获取intellisense的动机.智能感知,错误曲线和错误信息可理解性都是F#设计的工具因素.

很可能做得更好并推断更多(不牺牲其他经验),但我不认为这是我们未来版本语言的重中之重.(Haskellers可能会看到F#类型推断有点弱,但它们可能超过C#,他们认为F#类型推断非常强大.:))

也许很难以非破坏的方式扩展类型推断; 可以在将来的版本中将非法程序更改为合法程序,但是您必须非常小心地确保以前合法的程序不会根据新的推理规则更改语义,并且可能会出现名称解析(每种语言都可怕的噩梦)以令人惊讶的方式与类型推断相互作用.



3> Tomas Petric..:

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

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

另一个想法是从顶部到底部检查代码对应于我们如何读取代码(至少有时).所以,也许我们倾向于以支持类型推理的方式编写代码也可以使代码对人们更具可读性......


在你的最后一点,我可能以这种方式很奇怪,我倾向于以相反的方式对相关的函数进行分组(在让我这样的语言中).例如,假设我有一个复杂的函数C,函数A和B都使用函数C,然后我将函数从上到下排列为A,B,C.我想我喜欢这样读它因为实现解开的方式(告诉我大局,然后是细节).话虽这么说,我没有注意到F#部队的排序过多,尽管我还没有参与大型项目.
您喜欢的顺序是最自然的,因为它反映了评估的顺序.通过按值调用,F#方式更自然 - 特别是因为定义可能会产生直接影响.

4> Robert Harve..:

F#使用一次传递编译,这样您只能引用先前在您当前所在文件中定义的类型或函数,或者出现在编译顺序中先前指定的文件中.

我最近问Don Syme关于制作多个源代码来改进类型推断过程.他的答复是"是的,可以进行多次通过类型推断.还有单通道变量产生一组有限的约束.

然而,这些方法倾向于在可视化编辑器中提供错误的错误消息和较差的智能感知结果."

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


有趣.无论如何,我似乎没有为普通的F#功能提供很好的intellisense帮助; 当你执行Module.somefunc或使用一个类(它基本上杀死了类型推断)时,它似乎开始发挥作用.我想知道这种设计选择是如何的.

5> 小智..:

简短的回答是F#基于SML和OCaml的传统,而Haskell来自米兰达,Gofer等略有不同的世界.历史传统的差异是微妙的,但却是无处不在的.这种区别在其他现代语言中也是平行的,例如ML-like Coq与Haskell-like Agda具有相同的排序限制.

这种差异与懒惰与严格评估有关.宇宙的哈斯克尔方面相信懒惰,一旦你已经相信懒惰,那么在类型推理之类的事情上添加懒惰的想法是不费脑子的.在宇宙的ML方面,只要懒惰或相互递归是必要的,必须通过使用诸如with,and,rec之类的关键字来明确指出.我更喜欢Haskell方法,因为它导致较少的样板代码,但是很多人认为最好明确这些事情.


@JonHarrop那是真的.但它改变了代码的语义.很多人会和你争辩说,懒惰经常非常有用,并且可以采用不同的方法来解决问题.很明显,两者兼顾的能力是最好的,Haskell确实提供了这种能力,尽管偏向于懒惰的一面而不是像大多数语言那样严格的一面.
推荐阅读
k78283381
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有