在哪些方面使用F#比使用C#更合适?[关闭]


210

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

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

鉴于C#对这些功能特性的采用以及F#作为一种不纯净的功能语言的分类法(它允许您访问框架库或在需要调用某个函数时更改共享状态),尽管这两种语言都有其相似之处,但它们之间还是有很强的相似性与自己相反的主要重点。

我对您的生产多语言程序中采用这两种语言的任何成功模型以及您过去一年左右用F#编写的生产软件(Web应用程序,客户端应用程序,服务器应用程序)中的领域感兴趣,用C#编写。

Answers:


258

我编写了一个应用程序,以平衡电站组合的国家发电计划与能源公司的交易头寸。客户端和服务器组件使用C#,但是计算引擎使用F#编写。

使用F#来解决此应用程序核心的复杂性,清楚地证明了该语言在企业软件中的一个优势,即对大型数据集进行算法复杂的分析。我的经历是非常积极的经历。特别是:

度量单位我从事的行业充满了单位。我实现的方程式(通常是几何性质)涉及时间,功率和能量的单位。在测试和阅读/理解代码方面,让类型系统验证功能输入和输出单元的正确性可以节省大量时间。它消除了以前系统容易发生的一类错误。

探索性编程与更传统的编辑/编译/运行/测试循环相比,使用脚本文件和REPL(F#Interactive)使我在提交实施之前可以更有效地探索解决方案空间。对于程序员来说,这是一种很自然的方法,可以使他们对问题和游戏中的设计张力有所了解。

单元测试使用非副作用函数和不可变数据结构编写的代码很容易测试。没有复杂的时间依赖性交互作用可以解决问题,也无需模拟大量依赖项。

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

代码减少输入到计算引擎中的大部分数据都是矢量和矩阵的形式。高阶函数以最小的麻烦,最小的代码在早餐时吃这些东西。美丽。

缺少错误函数式编程可能会让您感到奇怪。我可以研究一种算法,尽力使代码通过类型检查器,但是一旦满足类型检查器的要求,它就可以工作。它几乎是二进制的,要么不编译,要么正确。最大程度地减少了怪异的边缘错误,递归和高阶函数消除了许多记账代码,这些代码引入了边缘情况错误。

并行性最终实现的功能纯正性,使其在处理数据向量时利用固有的并行性变得成熟。也许.NET 4发布后,这就是我下一步要去的地方。


18
+1解释为什么F#非常适合数字处理引擎。另一个(虚拟)+1,用于提及度量单位。语言的这一部分值得更多地提及。
cfern

5
很好的答案,相关的,当代的,概述了F#在处理复杂性方面的适用性,我从阅读中中学到了很多,谢谢
Peter McG 2010年

正如西恩(Don)昨晚提到的那样,他在最近的幻灯片中引用了很好的答案。是时候添加“添加到购物车”链接了吗?
克里斯·巴拉德

1
嗨,您可以告诉我们更多有关您的应用架构的信息吗?
Nikos,2012年

76

在Microsoft Research实习期间,我研究了Visual Studio IntelliSense for F#(本身是用F#编写)的某些部分。我已经从早期的C#项目中获得了IntelliSense的经验,因此我想可以将两者进行比较。

  • Visual Studio扩展性仍基于COM,因此您需要处理不是很好的.NET对象(并且绝对不能正常工作)的对象,但是我不认为C#和F#之间有任何主要区别(它工作正常)来自F#)

  • 用于表示F#中的程序代码的数据结构大部分是已区分的联合(C#不以任何合理的方式支持它们),这对于这种应用程序(您需要处理树形结构,例如程序代码)产生了巨大的差异。 )。区分联合和模式匹配使您可以更好地组织代码(将相关功能保留在一个位置,而不是在虚拟方法中将其全部保留)

之前,我还为F#(也用F#编写)开发了CodeDOM提供程序。实际上,我首先在C#中进行了实验,但随后将代码转换为F#。

  • CodeDOM提供程序需要遍历使用.NET对象表示的某些结构,因此没有太多空间来发明自己的数据表示形式(这是F#可以提供很好好处的领域)。

  • 但是,有许多小的F#功能使任务更加容易。由于您需要生成一个字符串,因此我定义了用于构建字符串的自定义运算符(使用StringBuilder),并使用它们和高阶函数(例如,格式化使用指定字符串分隔的对象的列表等)来实现代码,从而消除了很多重复(和繁琐的foreach循环)。

这是两个相对特定的示例,但它们都与处理程序或表达式的表示,或更一般而言,与复杂的树状数据结构有关。我认为,在这方面,F#绝对是一个不错的选择(无论C#的功能如何)。


6
非常有趣的是,更多的证据表明,Microsoft内部对F#的接受程度肯定很高,这一定是一个很棒的实习!
彼得·麦格

43

我们运送了世界上第一个用F#编写的商业产品(可视化的F#)和第二个(用于数字的F#)以及有关F#的第一个商业文献(《 F#.NET杂志》),并撰写和出版了有关当前版本的唯一书籍F#(Visual F#2010,用于技术计算)。

我们一直按照类似的用C#编写的产品来运输产品(例如this),但是我们在OCaml的商业使用方面也具有扎实的背景。当我们在2006年仍将F#用作研究原型时,我们就非常热衷于F#,因为我们认识到在工业强度的.NET平台上拥有像样的现代OCaml语言的潜力,因此,我们力求将其产品化。结果取得了令人难以置信的成功,F#远远超出了我们的崇高期望。

对于我们来说,F#具有许多不同的优点,我们将其用于各种应用程序。我们正在生产数十万行F#代码。现在,我们对所有 LOB应用程序都使用F#:使用F#代码处理信用卡交易,使用F#代码发送产品通知,使用F#代码处理订阅,使用F#代码完成帐户等。在这里值得关注的主要语言功能可能是模式匹配。我们甚至使用F#为语法着色来突出显示我们的最新书...

我们的可视化库是畅销书,其功能集中于在Visual Studio中运行的F#交互式。我们的库通过最小的工作量(例如,仅生成Plot([Function sin], (-6., 6.))绘制正弦波)。特别是,所有线程问题都是完全自动化的,因此用户不必担心UI线程和调度。编写库的这一部分时,一流的函数和惰性非常有价值,代数数据类型在其他地方得到了广泛使用。当我们的客户在WPF的命中测试中遇到性能错误并且可以轻松地在F#中重新实现相关代码以提高10,000倍性能时,可预测的性能在这里也很有价值。由于该产品的GUI具有自由格式的特性,因此GUI设计人员和C#不会受益。

我们的许多工作都围绕数值方法,包括我们的商业图书馆和书籍。F#在这方面比C#强大得多,因为它提供了高级抽象(例如高阶函数),而对性能的影响最小。在这种情况下,我们最引人注目的结果是从线性代数创建了一个简单但通用的QR分解实现,它比LAPACK的参考实现中的Fortran代码短20倍,比厂商调整的Intel Math快3倍。内核库和更通用的库,因为我们的代码可以处理任何类型的矩阵,甚至是符号矩阵!

我们目前正在开发F#(用于内脏)和C#(用于垫片)的WPF / Silverlight组件,构建WPF应用程序以充当我们软件产品的交互式手册,而我正在写一本新书《 Multicore F#》,将是.NET上共享内存并行编程的权威指南。


您与撰写“ F#for Scientists”的Jon Harrop是同一个人吗?
安德烈·阿特斯

7
是。我5年前为科学家写了F#。
乔恩·哈罗普

在倒数第二段中提到的F​​#中的QR分解代码是否有某种形式的参考?谢谢。
Samik R

@SamikR:不,对不起。那是商业代码。虽然很容易写。
乔恩·哈罗普

@Jon在多核F#上有字吗?
bigglesworth教授16年

25

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

该项目分为代表不同层的3个DLL。每层都有一个对应的单元测试dll。

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

这是我使用F#完成的第一个大型项目,我不得不说我喜欢这种语言。在许多方面,我都将此项目用作学习F#的方法(如果您仔细查看该项目的历史,这种学习曲线将非常明显)。

我发现F#最令人惊奇的地方就是它的语言简洁程度。Vim引擎包含大部分逻辑,但仅占整体代码库的30%。


19
编辑器...功能语言... vi仿真...您已经重新发明了emacs。NOOOOOOOOOOOOOOOOOOOOOOOOO!
Ben Voigt,2010年

2
除了它是“无100%认证的括号” :)
Pavel Minaev 2010年

@Pavel,当然还有元组和.net方法调用
JaredPar 2010年

26
这里需要注意两件事。首先,()在F#中不需要元组- ,运算符是创建let x = 1,2元组的要素,因此有效的元组已经没有任何括号。其次,F#中的任何配对括号都可以用成对的begin.. 代替end(这是从ML继承的)-例如,这"foo".IndexOf begin 'a', 1 end是一个有效的.NET方法调用。因此,如果您想成为无parens的人,F#是一种使您能够做到这一点的语言:)
Pavel Minaev 2010年

有趣的评论帕维尔!不知道 我认为,在某些情况下,与大编组块,我可能会更喜欢begin.. end。还:VsVim规则!
丹·菲奇

13

F#Visual Studio组件的许多单元测试都是用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传递给最终将调用OutputString和的其他组件,Clear然后string list ref在测试结束时检查该对象以查看是否编写了预期的输出。


有趣的是,越来越多的证据表明,Microsoft内部对F#的采用率很高。我不知道您可以创建在F#中实现接口的匿名对象
Peter McG,2010年

9

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

编辑以包括评论回复

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

这本来是可以的,但是要建立自己的解析程序会带来极大的痛苦。

本主题显示了其他一些建议,例如外部库,但是我们的首席架构师在使用功能语言方面是老手,因此使用F#的选择很容易。


+1您以前可能会用C#编写它,但由于某种原因它不合适还是较慢?
Peter McG 2010年

@Peter McGrattan至少在撰写本文时(软件),C#中没有lex / yacc实现。这本来是可以的,但是要建立自己的解析程序会带来极大的痛苦。stackoverflow.com/questions/540593/lex-yacc-for-c显示了其他一些建议,但是我们的首席架构师在使用功能语言方面是老手,所以选择使用F#是不费吹灰之力的
johnc,2010年

如果您认为C#没有lex / yacc,那么我很奇怪,您看起来并没有足够努力(比F#年龄大一点),说如果您需要lex / yacc,F#在我看来更适合锤子比c#钉子好
符文FS 2010年

我自己将f#与fslex / fxyacc一起使用,尽管不是在“生产”项目(无论如何尚未发布)中-MSIL语法突出显示和VS的代码完成扩展。使用F#的主要好处是可以获得ADT,这对于表示解析树非常方便。此外,使用拉链(en.wikipedia.org/wiki/Zipper_(data_structure))可以轻松进行增量词法化-并且,拉链具有功能性,更易于在F#中简洁地进行操作。
帕维尔·米纳夫

7

我目前正在为一种编程语言进行编译。编译器完全用F#编写。编译器(除了使用lex / yacc的lex和parser构建之外)基本上是作为对复杂树状结构的大量转换而构建的。

正如其他人所指出的,区别联合和模式匹配使使用这种数据结构比“在各处”将代码转储到虚拟方法中要容易得多。

在开始从事编译器工作之前,我没有做过任何F#工作(但是我必须在另一个名为MoscowML的OCaml变体中进行编译),正如Jared指出的那样,从代码中可以看出我首先做了什么部分,但总的来说,我发现F#容易在主要对OO进行编码十年之后,要学会重新进入FP思维定势将需要更长的时间。

除了使用树之外,我发现编写声明性代码的能力是FP(包括F#)的主要优点,该代码具有描述Im试图实现的算法的代码,而C#描述如何实现算法的算法,这是一个巨大的优势。


6

不是个人经验,但是您可以听DNR的一集(我认为是这一集),在那儿他们与Microsoft员工谈论F#。他们使用F#编写了大部分Xbox Live计分系统,该系统绝非易事。该系统在数百台机器上大规模扩展,他们对此感到非常满意。


5

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

http://research.microsoft.com/zh-CN/events/techvista2010/demolist.aspx#ThePathofGo

前进的道路:用于Xbox 360的Microsoft研究游戏

该演示演示了基于Go游戏的Xbox 360游戏,该游戏是由Microsoft Research Cambridge内部生产的。Go是东亚最著名的棋盘游戏之一,它起源于4000年前的中国。游戏欺骗性的简单性背后隐藏着巨大的复杂性。学习只需几分钟,但要花一生的时间才能掌握。尽管在国际象棋方面计算机已经超越了人类的技能,但为Go实施竞争性AI仍然是一项研究挑战。该游戏由Microsoft Research Cambridge开发的三种技术提供支持:能够播放Go,F#语言的TrueAI和与在线玩家匹配的TrueSkill™。该AI是用F#实现的,并满足了在Xbox 360的.net紧凑框架中高效运行的挑战。该游戏将您放置在许多视觉上令人惊叹的3D场景中。它是使用XNA环境在托管代码中完全开发的。

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


令人着迷:F#在XBox的紧凑框架上运行。FSharp.Core.dll和FSharp.Core.optdata FSharp.Core.sigdata是否不引用非CF程序集?
Peter McG

1
CTP附带了一个单独的FSharp.Core,它是为.NETCF构建的。(Silverlight还有一个单独的FSharp.Core。)
Brian

您说的这个CTP是什么?
Jwosty 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.