在哪些地方使用F#比C#更合适?

在过去的几年中,F#已经发展成为微软完全支持的语言之一,它采用了许多OCaml,ML和Haskell的思想。

在过去几年中,C#通过引入越来越多的function语言特性来扩展其通用function:LINQ(列表理解),Lambdas,闭包,匿名代表等等。

鉴于C#采用了这些function特性和F#的分类法作为不纯的函数式语言(它允许你访问框架库或者在函数被调用的时候改变共享状态),但是两种语言之间有很强的相似性自己极性相反的主要重点。

我对在您的制作多语种程序中使用这两种语言的任何成功模型感兴趣,并且还对在过去的一年中使用F#编写的生产软件(Web应用程序,客户端应用程序,服务器应用程序)用C#编写。

我已经写了一个应用程序来平衡发电站组合的国家发电时间表到能源公司的交易位置。 客户端和服务器组件是用C#编写的,但是计算引擎是用F#编写的。

用F#来解决这个应用程序的核心问题,清楚地表明了企业软件中语言的一个甜蜜点,即对大数据集进行algorithm复杂的分析。 我的经历是非常积极的。 尤其是:

计量单位我工作的行业里散布着单位。 我实施的方程式(通常是几何性的)处理时间,功率和能量的单位。 使用types系统validation函数的input和输出的单位的正确性在testing和读取/理解代码方面是非常节省时间的。 它消除了以前系统容易出现的一整类错误。

探索性编程使用脚本文件和REPL(F#Interactive)使我能够在比实现更为传统的编辑/编译/运行/testing循环之前更有效地探索解决scheme空间。 对于程序员来说,这是一种非常自然的方式来build立他们对问题和devise紧张的理解。

unit testing使用非副作用函数和不可变数据结构编写的代码是一个很好的testing。 没有复杂的时间依赖性交互作用,或者大量依赖性被嘲弄。

互操作我将接口定义到C#中的计算引擎,并在F#中执行计算。 然后可以将计算引擎注入到需要使用它的任何C#模块中,而不用担心互操作性。 无缝。 C#程序员不需要知道。

代码减lessinput到计算引擎中的大部分数据都是以vector和matrix的forms存在的。 更高级的function吃这些早餐,最小的麻烦,最小的代码。 美丽。

缺less错误函数式编程可能会感到奇怪。 我可以在algorithm上工作,努力让代码通过types检查器,但是一旦types检查器满意,它就可以工作。 它几乎是二元的,要么不会编译,要么正确。 奇怪的边缘案例错误被最小化,recursion和高阶函数删除了大量的引发边缘案例错误的簿记代码。

并行性由此产生的实现的function纯度使得它可以利用处理数据向量的固有并行性。 也许这是我现在要去的地方,现在.NET 4已经不在了。

在Microsoft Research实习过程中,我曾为Visual Studio IntelliSense for F#(本身用F#编写)的某些部分工作过。 我已经有了一些来自早期C#项目的智能感知的经验,所以我想我可以比较两者。

  • Visual Studio Extensibility仍然基于COM,所以你需要处理那些不是很好的.NET对象的对象(而且绝对不行),但是我觉得C#和F#没有太大的区别来自F#)

  • 在F#中用来表示程序代码的数据结构大多是有区别的联合体 (C#中不支持这种联合方式),这对于这种应用程序来说有很大的不同(需要处理树结构,比如程序代码)。 区分的联合和模式匹配允许您更好地构build代码(将相关function保留在一个地方,而不是在虚拟方法中遍布整个地方)

此前,我还为F#编写了CodeDOM提供程序(也用F#编写)。 我实际上是在C#中做了第一个实验,然后将代码转换为F#。

  • CodeDOM提供者需要遍历一些使用.NET对象表示的结构,所以没有太多的空间来发明自己的数据表示(这是F#可以提供很好的好处的地方)。

  • 但是,有许多小F#function,使任务更容易。 既然你需要生成一个string,我定义了构buildstring(使用StringBuilder )的自定义操作符,并使用它们和更高阶的函数(例如,格式化使用指定string分隔的对象列表等)来实现代码,重复(和繁琐的foreach循环)。

这些是两个相对具体的例子,但是它们都与处理程序或expression式或者更一般地说是复杂的树形数据结构有关。 我认为在这个领域,F#绝对是一个不错的select(不pipeC#中的function特性如何)。

我们发行了世界上第一个用F#( F#for Visualization )编写的商业产品,第二个( F#用于Numerics )以及F#( The F#.NET Journal )的第一批商业文献,编写并发布了唯一一本关于当前版本的书F#( 用于技术计算的Visual F#2010 )。

我们一直在用C#编写类似的产品(例如这个 ),但是我们在OCaml的商业应用方面也有很强的背景。 我们早在2006年就是一个研究原型的时候就热衷于F#的早期采用者,因为我们认识到了在工业强度的.NET平台上拥有像现代OCaml语言一样体面的潜力,因此我们推动了它的产品化。 结果取得了令人难以置信的成功,F#远远超出了我们的崇高期望。

对我们而言,F#有许多不同的优点,我们将其用于各种应用程序。 我们有数十万行F#代码正在生产中。 我们现在使用F#来处理所有的LOB应用程序:使用F#代码处理信用卡交易,使用F#代码发送产品通知,使用F#代码处理我们的订阅,使用F#代码等完成我们的帐户。 也许在这里支付股息的主要语言特征是模式匹配。 我们甚至使用F#语法突出显示我们最新的书…

我们的可视化库是一个大卖家,其function集中在Visual Studio中的F#交互式运行。 我们的图书馆能够以最小的努力产生交互式的二维和三维可视化(例如, Plot([Function sin], (-6., 6.))来绘制正弦波)。 特别是,所有的线程问题都是完全自动化的,所以用户不必担心UI线程和调度问题。 编写这部分库的时候,一stream的function和懒惰是非常有价值的,代数数据types在其他地方被广泛使用。 当我们的客户在WPF的热门testing中遇到性能问题时,可预测的性能也被certificate是有价值的,并且能够轻松地在F#中重新实现相关代码,从而获得10,000倍的性能提升。 由于该产品GUI的自由forms,GUIdevise器和C#将不会有好处。

我们的大部分工作都围绕数字方法展开,包括我们的商业图书馆和书籍。 F#在这个领域比C#强得多,因为它提供了高级抽象(例如高阶函数),而且性能损失最小。 在这种情况下,我们最引人注目的结果是创build了一个简单但是通用的线性代数QR分解实现,比参考实现的LAPACK的Fortran代码短20倍,比厂商调整的英特尔math内核库和更通用的,因为我们的代码可以处理任何types的matrix,甚至符号matrix!

我们目前正在开发WPF / Silverlight组件,这些组件包括F#(用于胆量)和C#(用于垫片),构buildWPF应用程序以充当我们的软件产品的交互式手册,并且正在撰写一本新书 – 多核F#将成为.NET上共享内存并行编程的权威指南。

在过去的6个月左右,我一直在为Visual Studio 2010开发Vim仿真层。它是一个免费的产品,所有的源代码都可以在github上免费获得

  • GitHub: http : //github.com/jaredpar/VsVim
  • Visual Studio Gallery上的 VsVim

该项目分为3个DLL代表一个独特的层。 每个图层都有相应的unit testingdll。

  1. Vim引擎:F#
  2. 用于装饰和编辑器集成的WPF层:C#
  3. Visual Studio集成层:C#

这是我用F#做的第一个重大项目,我不得不说我喜欢这门语言。 在很多方面,我使用这个项目作为学习F#的一种方法(如果你仔细观察项目的历史,这个学习曲线是非常明显的)。

我发现F#最令人惊奇的是它是一种语言的简洁。 Vim引擎包含了大部分的逻辑,但它只占整个代码库的30%。

很多F#Visual Studio组件的unit testing都是用F#编写的。 他们在VS外面跑,嘲笑各种Visual Studio的位。 能够使用实现接口的匿名对象代替模拟框架/工具是有用的。 我可以写

 let owpe : string list ref = ref [] let vsOutputWindowPane = { new IVsOutputWindowPane with member this.Activate () = err(__LINE__) member this.Clear () = owpe := []; 0 member this.FlushToTaskList () = VSConstants.S_OK member this.GetName(pbstrPaneName) = err(__LINE__) member this.Hide () = err(__LINE__) member this.OutputString(pszOutputString) = owpe := pszOutputString :: !owpe ; 0 member this.OutputStringThreadSafe(pszOutputString) = owpe := pszOutputString :: !owpe ; 0 member this.OutputTaskItemString(pszOutputString, nPriority, nCategory, pszSubcategory, nBitmap, pszFilename, nLineNum, pszTaskItemText) = err(__LINE__) member this.OutputTaskItemStringEx(pszOutputString, nPriority, nCategory, pszSubcategory, nBitmap, pszFilename, nLineNum, pszTaskItemText, pszLookupKwd) = err(__LINE__) member this.SetName(pszPaneName) = err(__LINE__) } DoSomethingThatNeedsA(vsOutputWindowPane) assert( !owpe = expectedOutputStringList ) 

当我需要例如一个IVsOutputWindowPane实例传递给最终会调用OutputStringClear其他组件时,然后在testing结束时检查string list ref对象,以查看是否写入了期望的输出。

我们使用F#中的Lex-Yacc实现编写了自定义规则引擎语言,

编辑包括评论回复

在C#中没有lex / yacc实现。 (就我们所知,而F#则是)

这本来是可能的,但是我们自己build立parsing是一个彻头彻尾的痛苦。

本主题显示了一些其他build议,例如外部库,但是我们的首席架构师在function语言方面是老手,所以使用F#的select是不容易的。

不是个人的经验,但是你可以听一段DNR(我认为就是这个 ),他们和微软的人谈论F#。 他们使用F#编写了绝大多数Xbox Live评分系统,这远非易事。 这个系统在数百台机器上大规模地扩展,他们对此非常满意。

WebSharper人已经构build了一个以F#为中心的完整产品。 这里有一篇文章谈论它:

http://www.sdtimes.com/content/article.aspx?ArticleID=34075

下面是关于一个使用F#和C ++ / COM的银行的案例研究:

http://www.microsoft.com/casestudies/Case_Study_Detail.aspx?CaseStudyID=4000006794

我目前正在编写一种编程语言。 编译器完全是用F#编写的。 编译器(除了用lex / yacc编译的lex和parsing器)基本上被构build为像结构这样的复杂树的转换。

正如其他人所指出的那样,工会和模式匹配的区别使得使用这种数据结构比使用虚拟方法在“遍地”倾销代码要容易得多

在我开始编译编译器之前,我还没有做过任何F#工作(然而,在另一个名为MoscowML的OCaml变体中我编译了编译器),就像Jared指出的那样,从代码中可以看到我先做了哪些部分,但总的来说,我发现F#学习主要面向OO十年之后,再次学习FP的思维设置将需要更长的时间。

除了树木之外,我发现编写声明性代码的能力是FP(包含F#)的主要优点,其代码描述了Im试图实现的algorithm,而C#描述如何实现algortihm,这是一个巨大的优势。

我不知道它是否在制作,但是“The Go of Path”的AI是用F#编写的:

http://research.microsoft.com/en-us/events/techvista2010/demolist.aspx#ThePathofGo

Go的path:微软Xbox 360的研究游戏

这个演示展示了一个基于微软研究剑桥公司内部生产的Go游戏的Xbox 360游戏。 Go是东亚最着名的棋类游戏之一,它起源于4000年前的中国。 在游戏的欺骗性简单背后隐藏着巨大的复杂性。 学习只需要几分钟,但需要一辈子才能掌握。 虽然计算机在国际象棋方面已经超越了人类的技能,但是为Go执行一个有竞争力的AI仍然是一个挑战。 该游戏由微软研究剑桥公司开发的三项技术提供支持:一种可以玩Go,F#语言和TrueSkill™的AI来匹配在线玩家。 人工智能是在F#中实现的,能够满足在Xbox 360上的.net精简框架中高效运行的挑战。这款游戏将您置于一些视觉上令人惊叹的3D场景中。 它在使用XNA环境的托pipe代码中完全开发。

(其他人已经提到“TrueSkill”了。)