BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

Don Syme谈F# 2.0——VS2010中的新晋头等公民
录制于:

| 受访者 Don Syme 关注 0 他的粉丝 作者 Sadek Drobi 关注 1 他的粉丝 发布于 2010年7月1日 | QCon上海2018 关注大数据平台技术选型、搭建、系统迁移和优化的经验。
52:08

个人简介 Don Syme是F#的主要设计者。他也参与了C#泛型和.NET CLR的设计。他于1998年加入微软研究院,1999年从剑桥大学计算机实验室获得博士学位。

QCon全球企业开发大会(QCon Enterprise Software Development Conference)是由C4Media媒体集团InfoQ网站主办的全球顶级技术盛会,每年在伦敦、旧金山、北京、东京召开。自2007年3月份在伦 敦召开首次举办以来,已经有包括金融、电信、互联网、航空航天等领域的近万名架构师、项目经理、团队领导者和高级开发人员参加过QCon大会。

   

1. 我是Sadek Drobi,我在QCon现场,同Don Syme再次会面。那么Don,将近有2年或2年多了吧。自从上次采访,你在F#和其他方面有什么进展?

我觉得我们是在埋头于Visual Studio 2010方面的工作,也快完工了,目前技术工作已经完成,最后还有一些小细节需要完善,接着就可以发布了。在Visual Studio 2010中,你可以用到F#,当然在Visual Studio 2008中也可以,你还可以在Linux和Mac上通过Mono来使用它。我们总是提醒人们,它不仅仅在Visual Studio 2010才能用到。

   

2. 有意思。你们实际上维护了一个2008的版本,一个2010的版本,那么说起来人们就不必为了使用F#而一定要运行.NET 4.0。

在设计过程中,我们有一些有趣的地方,例如关于是否依赖.NET 4.0这个问题,我们认为对于F#而言,能够完全跨平台是非常强大的一个特点,这不仅仅限于.NET 2.0、3.5、4.0,也包括Mono和Silverlight以及Moonlight。基本上,在我们考虑跨平台问题的时候,倾向于认为(当我们使用跨平台这个词的时候,你也立刻就应该想到)是跨Linux、Mac和Windows。不过现在世上的平台也发生了变化,云我们也要考虑进来,甚至也不得不考虑客户端的东西,比如在Silverlight中,我们还要考虑手机平台。

虽然现在的F#,你还不能看作是一个重要的移动电话编程语言;不过还是有所关联的,或许在某一天我们要在所有平台上都运行它,让这个语言可以做更多可行的开发工作,比我脑海中想到的还更多。当然,如果你可以在Visual Studio 2008中使用F#,在没有Visual Studio的Windows系统上使用,也可以通过Visual Studio 2008 Shell来使用,可以通过Visual Studio 2010来使用,你也能在Linux系统上通过Mono来使用。在Linux和Mac系统上,我们特别测试了在Mono 2.4到2.6的运行情况。

   

3. 我也注意到,你们后来还添加了一些功能到F# Power Pack中——我的意思是和LINQ的集成以及其他方面。

最近这两年是很有趣的时间。当然,我们做了大量的设计调整和错误修正,并同大量的F#用户和采用者一起工作,不过F#的很大一块工作是研究项目,所以它实际上被分成了两个部分。一部分是我们认为的这个语言的一些核心功能,我们需要悉心维护;另外还有大量的工具方面的事情在项目启动的时候就已经开始在做,这些功能显然也很有价值,不过我们不打算花太多精力去维护。当然,我们也希望这样的功能也能最终得以发布。

我们花了很长时间来考虑,如何保证这些功能可被社区所用。最后,我们在CodePlex创建了Power Pack,一个基于微软公共许可协议(这是一个获准的的微软开源协议,即OSS协议)的开源函数库。它首先包含了一个兼容函数库,以及一个数学运算库,有 Lex和Yacc函数库,也有一些异步编程辅助函数,随着时间推移还会有很多功能。确实是,这种方式就是我们一直寻找的。

   

4. 你能和我们说说LINQ的功能不?

嗯,当然,这个功能就是查询集成。这个东西我们确实希望能放到核心函数库中。这也是其中一个先在power pack中发布,经过一段时间后会放到核心函数库中的功能。这是个非常好的特性,基本上可以让你在F#中嵌入对数据库的查询来完成C#那样风格的LINQ 编程。LINQ已经被广泛运用,我们很高兴能在power pack为大家也提供这样的功能。大家不妨一试。我已经撰写了一篇博文,讲述如何在F#中使用LINQ查询的基本知识。

   

5. 在F#的包【译者注:即类似C#的命名空间】中有Quotations,那么说你们有函数库来处理引用语句,对吗?

对,就是在核心F#函数库中。核心F#函数库就是用来构建额外丰富功能的一切基础。Quotation就是其中一个。让你在F#代码中可以处理表达式树。这个功能也揭示了一个问题,就是F#的下一步要实现什么,以及一个重要的现象就是F#的功能特性实际上被做了分支,这也就是我们称之为版本2的原因,这个版本也即现在大家拿到手的版本。我们把研究中的F#称之为F# 1.0,而现在它已经成为F# 2.0了。

Quotations真的是一个令人非常激动的特性,会带来很多潜在的应用。例如,一个应用之处就是LINQ查询支持,可以在power pack找到;另外一个应用就是把F#代码转化到GPU指令,在GPU中以数据并行的方式运行,这确认让人振奋。还有一个应用领域是,把F#代码转化为 JavaScript,它被使用这项技术的Intel公司里的人称之为一个伟大的开端(实际上,我甚至都不认为它是个开端),我有一个出色的F# 2.0 JavaScript框架能让你在客户端编程中使用F#。

   

6. 实际上你可以转换得到所有代码?

所有的,而且如果你愿意的话,能用F#来选择处理HTML的任意部分,事实上正如DSL所做的那样。你实际上也可以进行异步编程。在客户端,你当然需要进行大量的对服务器的异步请求。让我吃惊的一点就是,对于Web编程,你需要知道如此多的语言。

你必须知道HTML,必须知道CSS,必须知道SQL,必须知道类似C#这样的编程语言,大概还有1到2种语言标记语言也要知道,例如 ASP.NET标记语言。那么多东西需要知道,让人望而生畏。而现在,我能使用F#引用功能,一般而言它能以一种很妙的方式把这些功能进行简化。

我想这就是很多人在寻找的解决当今编程过程中遇到的一些挑战的功能,在进行Web编程过程中,我们急切地需要对其简化和强类型化。

   

7. 当我提到F#的时候,通常每个人都认为它就是一种主流语言或主程序,只不过语法和F#的属性更适合表示数据而已。

是的,假如那样的话,我们就能在HTML中表示数据,由于F#的部分代码能被转换为JavaScript代码,这样也能表示JavaScript。就像你正在编写运行在JavaScript中的F#一样,这确实是一个非常让人兴奋的开发框架。

   

8. 我能把F#用于保存配置信息的配置文件,或任何不算是真正代码的东西里?

对于保存配置信息,我们确实把F#用作一种更丰富信息表示方式,这样将变得常见。通常,数据都是从外部的日志文件读进F#,你不太会考虑用F#来表示数据。在F#编程中,你能用F#表达式作为数据表示方式,而不用引入某种新语言或技术。你也不用去采用一种新的文件格式,对于一个或两个数据结构或数据表,你能轻易地在F#中实现它,且可以得到强类型的功能,并立马就能对这些数据进行操纵。

   

9. 另外,F#有一种FSX扩展,它是一个脚本文件。能用它来在Windows或其他操作系统中,做一些构建脚本或任务执行脚本吗?

当然。F#可以作为脚本语言的,我们把fsx看作是编程脚本。你可以以脚本的方式来进行编程。我们并不鼓励用F#来开发所有类型的脚本工作。也许,有些人已经编写了一些脚本文件,或已经有他们喜爱的脚本语言,比如在Windows上的PowerShell。或者在Apache用的一些脚本,或在 Unix系统上某些脚本。

不过,也许在进行日志文件分析或编程的过程中,如处理被混淆过的文本文件,处理正则表达式匹配,或处理类似于跨文件搜索来做一些文件内容分析的时候,会遇到一些限制。这样的限制都比较棘手。某些限制,你或许能使用一些外部的工具能进行解决,不过在某些时候,用FSX文件将让你十分轻松的解决问题,只需在Visual Studio中通过Control-N来新建FSX文件,或在emacs或其他编辑器中也可以编写FSX文件。

   

10. 你能使用F#的强大异步功能来完成这些工作。

例如,你能利用变换来使他们更适合使用并行功能。接着,你可能做的就是。把数据源进行某种变换,例如对于日志文件,接着开始构建一段分析代码,然后在完整的数据集上实际运行,可能会有几G的数据,这样你认为“好,这个程序已经写好了,它是有用的,它是用F#编写的,将要花费2周的时间来处理这些不同的数据集。我们可以不用对这些数据进行分区。”你可能会手动进行分区,或最好是进行并行处理。

   

11. 每次,在提到诸如多核和并发编程的时候也会提及F#。那么F#在这方面的强大之处是什么?为什么每个人都把F#和异步编程放到一起讨论?

实际上,这就是我今天要在QCon上讨论的话题。他们要我不仅仅谈论F#编程和并行编程,也要更多谈一些关于函数式编程和并行编程的常见话题。在这两方面,存在有趣的重叠,因为我不仅仅在谈论函数式编程,也在让大家听到除了并行编程本身的东西外还有函数式编程的基本原理。

函数式编程,是一种很奇妙的编程范式,用于面向大量数据的工作和引擎,或一般用途的编程,不管你用不用并行编程。不过这有一定的重叠,我尽量用各种方式来描述这些重叠的特征。一个基本事实是,所有的函数式语言都鼓励你在应用程序中最小化和减少状态数,根本来看,就是要在所有代码中都使用不可变数据结构。

F#代码中贯穿了很多不可变模式。F#的一个特别强大的应用领域就是任务并行处理。你可以回顾一下.NET 4.0 任务并行库。F#也存在一个特别的函数库称之为异步库(Async Library)。它很有意思,因为能让你混合IO的并行处理,比如在你并行地抓取一组网页的时候,或并行地伺服一组TCP的服务器端请求的时候,你可以把这些处理过程和某些CPU计算过程混合在一起。

你有大量的请求进来,你实际上是获得了一个独立的小任务,比如响应任务。它不是线程,因为无论何时需要从后端数据库获取数据的时候,它都会以一种轻量级睡眠模式进入睡眠。在你获得进入的请求的时候,我的意思是很多请求,如50000个同时进入的请求或类似的通过TCP通道进入的东西,都需要对这些请求作出响应,接着去和后端数据库打交道,并异步地返回的这些请求。这种程序在F#中非常容易编写,因为它实际给了你一种轻量级任务模型,尤其适合处理那种不大的IO处理和CPU运算。

   

12. 对于“轻量级”,你的意思是不是没有线程那样昂贵?

是的,你能在单独的进程中创建50000个任务。某些情况下,你不需要这样处理。比如,你要同时伺服10个请求,这样你完全有资源为这些请求每个创建一个线程。有趣的是,虽然如此,在你设计一个服务器端系统的时候,需求可能会不断改变。你要考虑到,在某些服务器上可能需要处理计算非常昂贵的视频解码工作,而过一会,你把这部分工作移交给其他后端服务的时候,前端服务器实际上突然变得非常类似电话交换机那样。

“电话交换机”忙于收到呼叫,传递呼叫,共享信息,需求变化的非常快。你所认为的伺服10个请求的情况,会突然变为要伺服成千上万的请求,因为负载均衡被改变了。这类重量级的服务器端异步编程,在F#中可被轻易地完成,最近这个话题已经成为我特别感兴趣的一个。以商务的口吻来说,“我们有非常优秀的特性集”。

在F#中的这种处理轻量级响应代理或任务的机制,显然是一种构建很多不同应用的好机制,不管在客户端还是服务器端,我们会提供相应的功能分支给你来构建所需的应用,在什么时候使用何种机制也依赖于准确的性能权衡。我们确实一直都很高兴,能发布这些特性集,这种不同的编程模式,能够解决非常复杂的任务。

   

13. 在F#中异步编程是相当常见的目的。我也看到一些使用异步编程来轻易实现的Actor模型例子。

构建轻量级代理有一个基本原理,就是你启动一个Actor,启动一个消息通道(cues),所有东西都用消息通道来处理。那样做很好,也是Erlang所用的模型,不过我实际上感兴趣的仅仅是更底层的东西,就是整个轻量级异步机制。

Actor只是你可以构建的一个东西而已,你还可以构建TCP请求处理程序,它可不是Actor。你也不想为每个请求都创建一个消息通道,因为那样过于昂贵。我非常高兴,异步机制似乎在多得惊人的应用中都能起到作用,而Actor只是其中一种应用。

   

14. F#提供了这些类型的任务,对吗?类似处理请求的任务?

在服务器端,我们正在计划放这样的东西到Power Pack中替代辅助类,来帮助你更好更容易地构建TCP服务器。在F#中,你也可以在C#中使用的标准TCP代码,也可把相应的诀窍用到F#中,也可以看一下最近F#提供的一些示例。作为一个构架师,我的大部分工作是轻易让你构建能处理5000或10000并发请求的服务器端系统。

有时,如果你的Web 2.0公司获得成功,拥有20000人,你就需要另外的服务器了。那样,你可能打算把应用转换为云计算。我现在非常感兴趣,如何把一个正在运行中的伺服所有这些请求的F#异步应用程序,立刻地迁移到微软的Azure或Amazon的EC2或能找到的各种云计算平台中去运行的转换点。

要研究那个转换点,我们常常通过一些代码来实践,并构建一些重要的示例,来辅助大家把应用程序的生命周期过渡到下一阶段,我真的喜欢做这样的事情,因为你可以通过这种方式学到关于云计算的很多东西。既然如此,我当然利用Windows Azure来开展这个工作,我可以说,很高兴我能做到非常平滑地进行转换。

你有一个服务器端应用程序,它使用了特别的TCP通道,你只用把它部署到Azure中,并为自动负载均衡进行一点调整,那么云计算服务器就能做和你在F#中完成的同样事情。第一次使用Windows Azure,只工作了一个晚上,我们就开发出了一个可伸缩的应用程序。我们将能任意伸缩,只要你购买了足够多的云计算资源,你就能伸缩到支持数以亿计的同时请求。

我真的很高兴,这样的转换能正常工作。我认为,使用web作为数据源是一种绝妙的方式,作为一个数据分析者,同样还是可以使用F#作为编程工具来访问这样的数据源。例如,你可以连接到一个金融数据源,通过这种新的编程访问方式来获取金融数据流,来进行相关分析工作,这会是一个很棒的方法。

在服务器端,绝妙之处在于可以作为这些数据流的实现语言,这些数据流的提供器,或许更好地从其他数据流中进行匹配。你获取某些数据流,构建某个分析引擎,并基于Web依次提供。我想这非常有意思,为F#这样的语言而振奋,因为它把F#的强大体现到了数据分析的应用当中,也同时能得到很好的封装边界。

我们知道,Web服务器或Web的REST API要让外部访问,当然你可以使用任何语言来开发,不过不希望强制你的客户端也必须用同样的语言来开发。对于这样的函数库,当然是件好事,不过对于类似提供数据服务的这样的情况,你显然不得不通过一些更通用的API来进行部署,以便让任何其他语言都可以访问。

   

15. 这是F#的下一步要做的,对吗?

我想这是F#的一个精彩应用领域,有时候,我认为F#是进行Web 2.0开发的完美语言,可以处理哪些除了UI以外的数据分析工作。我们也看到某些使用F#开发的机器学习应用程序,F#也用于广告引擎,也用于微软系统中的庞大预测引擎。我想这是一个很奇妙的应用领域。函数式编程世界也有这样一股趋势,更多关注于老式编程方面的东西。你姑且认为是Fibonacci运算这一类的例子,以及由此引发的一些东西。

   

16. 你提供了一些根据实践性编程的F#例子没有?

是的,这也是我正在讲述的工作的很大一部分。我们努力研究,并展示如何在这类工作中使用F#异步编程。

   

17. 人们现在开始学习F#——他们大部分都是C#、Java或其他的程序员,他们看到这个是一个基于ML的编程语言。这对于他们是非常陌生的,所以他们开始提出一些问题,比如“我应该在什么时候使用函数,我应该在什么使用使用方法,应该在什么时候使用类、对象,或我应该在什么时候使用Union Type?”,对此你有何看法?

我们在最近一年中大部分工作都是,确保大家在遇到这些迷惑的时候都能尽可能顺利理解。在某种意义上说,不管你使用静态方法还是模块中的函数,问题都不大。从编程的角度看,两者的区别也非常少。在某个特别的例子当中,静态成员确实允许你进行重载。这可能需要更多的设计,而使用模块和函数,就需要不同名称或更好的推断类型,这样才能相对简单明了。不过在一定的运用程度,你如何使用都无所谓。

对于实现代码这点而言,这样的讨论是无所谓的,实际上,我们确实听到一些有面向对象编程背景的人们在用F#进行面向对象的编程。你会注意到,由于使用函数来代替之前不得不创建的其他类,或者使用F#对象表达式来避免仅仅为了实现抽象方法而创建的子类,你会突然发现大量的类就会随之消失。

某些面向对象设计模式逐渐趋同为这种简化版本的更佳的OO编程,接着,使用函数式编程的人们也倾向于放弃原有的编程结构。也许,如果他们来自于同样的ML背景,甚至都不会使用任何面向对象编程的思想,不会封装可变状态,接着,他们会突然发现在F#中封装可变状态是很不错的。

那么,通过这样的转变,基本上你可以非常恰当地运用面向对象编程——封装固定类型,某些很好封装的接口类型,并把这些隐藏到实现背后。实际上,我们可以在F#中看到两个编程流派,并可以在中间找到一个很好的平衡点。

   

18. 在F#中的函数库里,有时你会看到一个Option类型返回,有时又是异常返回。有什么规律或技术可以遵循吗?

我们很愿意收集来自F#社区中为F#设计函数库的人们的诸多问题。我们倾向于在函数库设计(那种鼓励人们非常直率地作出决定的东西)区别对待,我们称之为香草(Vanilla).NET函数库设计,那种你绝对会用到任何其他.NET语言中的函数库。

F#函数库有着F#风格的设计,那种能运用在应用程序的内部构架中,或者开发的一系列函数库,或构建一个F#的特定框架。当然,在后者中,你能更自由地使用F#的特定结构。例如,如果你完全在进行一个香草.NET函数库设计,那么你应该遵循常规的.NET函数库设计准则,有很多非常了不起的准则的。比如,有准则会讲到什么时候使用结构体——你只需去阅读相关的.NET设计准则就行。

在使用异常方面,它也会给你很好的建议,给你很好的准则。在用于F#的F#函数库中,如果真的要把这个函数库(如F#调用函数库)作为一个长期维护的代码,那么F#语言的特定特性实际上在这这方面的有所实现,或只是给出关于函数库设计的提示。F#在某种意义上影响着函数库的设计,比某些函数式编程拥护者所认为的要少,不过在某些地方确实还是对用于F#的F#函数库设计有所影响。让我们来举个例。

如果你编写了一个函数,它本身是异步方法,那么你可以调用它,并异步地给你返回结果。接着,F#代码中所蕴含的模式理所当然会以异步类型或异步 String返回,可以包含各种内容。你可以运用到用于F#的F#代码中的一些惯用法。我们来看另外一个例子——表达式树。在API边界上,你会遇到某种差异并集(discriminated union)。

其中有很多充分的理由,为了软件工程把差异并集的表现掩盖在了某些基本的用于创建差异并集元素的API背后,而且也不必分析它们。比方说,Java 视图API就是一种差异并集,表示了命题(propositional )对象或底层的某些东西。你大概不需要在外部显示它,从软件工程的角度看这也不是一个好主意。

就算F#具备这些特性,也不意味着在API边界,就因为你打算把自己开发的函数库进行长期维护,就要掩藏它们废除它们。例如,进入你的函数库的实际数据可能来自XML,也可能来自JSON格式。

不一定要F#程序员来编写那个函数库。我们为这两个例子中提供一系列准则——香草.NET函数库设计,以及用于F#的F#函数库设计。我们将通过F#社区来推进这些准则,通过与F#社区和其他F#用户合作,来了解这些准则是否适合,所以我们期盼大家的反馈。

   

19. 在F#的设计过程中,你尝试尽量少用特殊的功能。甚至对于我们能用到的首要功能,文本机制也是如此?

我们之前聊过这个话题的。我想,你指的是经常用到的语言元素,让我们以异步编程或数字文本来说明。你知道,要把某个功能放到语言中,总有一个或两个特殊的原因。你有一个大整数,想编写一个为3亿的整数,那么我们就提供了大整数类型,不过10%到5%的用例中,人们实际上需要改变这些文本的意思。

例如,有各种不同的大整数函数包,总有一个充分的理由会突然决定转换到不同的函数包上。在语言中,你不能把机制仅仅绑定到一个底层类型上,应该尽力让它表示不同类型,如果我们会以各种方式来使用它那么也会映射到不同类型上。在F#异步编程中,我们也同样地这样处理。你可以定义自己的计算表达式(Computation Expression)构建器,让其能够在异步编程上实现不同的变化。

   

20. 计算表达式不是专用于异步编程的。是一个通用的功能?

它是一个通用功能,在F#中它实际上也是很有意思的方面,人们有时看到F#计算表达式,他们会说“这是Haskell的单元(monads),那么他就是用于单元的某种机制。”实际上,它不仅仅是用于单元的机制。它也是用于类群(monoids)的机制,基本上说来,它类似于Haskell的列表表达式或Python中所理解的那样。

有趣的是,你能使用这个人们都知道的东西来实现它,比如F#中的序列表达式,当然也有类似异步序列这样的东西可用。你希望获得返回结果的流,比如说 Twitter数据。比方说,你想订阅某个特定用户名下的所有消息,那么Twitter将给你一些API来完成这项工作,这样查看这些数据流的方式自然可以多种多样。

查看它的方法是将要提到的异步序列。基本上,每次你想查看下一条信息,程序就会进入一个轻量级的睡眠状态,直到下一条信息到达,才“醒”过来。这让你,可以启动很多同时的响应器来处理进入的事件字符串。F#计算表达式语法让你能够轻易地定义异步序列,由于这个非常通用的机制让你既可以完成单元处理也可以完成类群处理。这很了不起。

   

21. F#是函数式编程语言,也是面向对象编程语言。你如何进行设计,以便面向对象的特性不会影响函数式编程的特性,或反过来说,如何保证函数式编程的优势而不损害面向对象的特点的?

某种意义上,这是由于F#的历史所带来的。熟悉F#的人们应该知道它是作为核心ML的实现,也即第一个OCaml语言的核心而开始的,其本身非常类似于我所使用的第一个ML版本,就是Edinburgh ML。它尽力去保证这种编程范式的基本优势。在他的核心中,总是有那样的远见,我们从来不用去维护它。

不过,也不意味着我不用去做一些折衷,或在某些领域的设计改变,比如我们要额外支持重载。比如,我们也使用F#的额外底层类型添加了两个64位的整数类型,两个32位的整数类型,这实际上和OCaml语言的设计是有所不同的。但是,也说明了,由于我们添加了面向对象的概念,就要花更多的精力去保证它们能容易的在函数式编程的上下文中使用。

回到几年前,大约4年前,当我们做出有关面向对象编程的决定的时候,这个关键的设计决策不仅要涉及命名类型(nominal types)的使用,也要在软件工程和编程过程中接受命名类型的角色。函数式编程世界的传统总是使用同样的构造类型(structural types)。如果你打算进行函数式的面向对象编程,那么总是会用到构造类型和兼容于构造类型的东西,其中涉及很多重要的理论,有数个优秀的实现可以在实践中展示它能很好的运转,包括类型推断。

比如,OCaml对象系统就是其中一个。当我们刚开始涉及.NET函数库的时候,我们只是作为对函数式编程具有一些特别见解的语言研究者,而当我们提出相关的函数库设计原则的时候,在早先的几年中已经积累了一些经验了。我们可以把C#看作是面向函数库的语言。这是一个伟大的编程语言,不过他们把它的第一个版本称之为面向组件的语言,一个为编写.NET函数库和.NET组件的语言。这就是为什么在这个语言的第一个版本中就具有属性,具有事件。

我们说“没问题”,接着就由函数库设计来驱动我们的工作,他们也遇到了一些难处理的规格,就是我们希望构建的这个函数库,需要语言来完成。他们没有接纳构造类型或类似的方式。构造类型不是编写优秀函数库的必要元素。它有一定用处,可以有用武之地,不过不是必要的,同时这真的为我们提供了学习实践—— 实际上命名类型和名称在函数库设计中更重要,因此,在F#面向对象世界中,你会看到很多数量超乎你想象的命名类型。

有趣的是,这也有很多优点。让你的类型推断问题简化了,帮助你更多地使用智能感知,比如实际上你可以把在程序中从头到尾的很多类型都声明为一种特别的命名类型。我想在某种意义上而言,这是一个关键的设计决策,放弃了函数式编程理论思想的一些东西,而接受了更多软件工程的现实。我的老板,Luca Cardelli在面向对象问题上,具有的非常清晰的见解就是关于软件工程的,函数式编程更多地是为了在编程中更少代价地实现代码和功能融合。这真的有助于指导我们做出某些设计决策。

   

22. 你刚刚提到智能感知。我猜,Visual Studio如今可以支持智能感知和F#的调试了。对于一个函数式编程语言来说,为F#实现智能感知是否更加困难?

因为它是一种类型推断语言,在类型推断语言中确实做了一些折衷。C#智能感知的实现绝对一流,我们也很高兴在F#中能提供这样的功能,虽然它在某些地方还有点粗糙,你可能需要在代码中放置一点点类型批注(annotation)。固定的类型信息越多,智能感知的体验变得越好。我们也非常高兴能让你的 F#代码获得自动背景类型检查的功能,不用说,我想这是在IDE中一个绝对重要的功能。

从推断类型中获得信息也非常有用。在编写代码的时候你就可以检查大部分代码,而在鼠标悬停到代码之上的时候还可以看到推断出的类型。调试体验——我们同样很高兴能为大家提供这个功能。它能起到一定作用,当然在F#中对代码的执行有着严格的顺序,我们关心的主要事情是,很好的断点体验和很好的逐步调试体验。

我们主要关注开发代码(grade code)的调试,而较少关注优化代码(optimized code)的调试。在调试优化代码的时候做出了一些折衷,你依旧能用它,不过我们做出了一些有趣的折衷。在调试开发代码的时候尾调用在默认情况下是关闭的,因为它们会影响调试体验。当然,对于用于直接目的的立即循环,尾调用还是能发生,不过如果尾调用是互相递归且用于非直接尾调用,或如果你编写的代码非常依赖于尾调用(在F#中,要绝对依赖尾调用的情况是少之又少的),而且你还希望运行在调试模式下,那么你可能不得不显式地打开尾调用。这也很容易就办到。无论如何,我们很高兴为大家提供了调试功能。

   

23. 我们谈到了F#文件的两种格式,还有第三种,就是F#接口文件。你能简单谈一下F#接口文件?

是签名文件。当然,这也有意思,因为我非常熟悉那些使用过OCamel的人们。在Java中,每个类都是一个单独的文件。在F#可以不这样做。你通常会有一个相当大的实现文件。就算只有一个文件实际上也会代表你的构架实现中的整个层,或整个组件,比如在F#中的类型检测器就是一个大文件,又或名称解析引擎,在Java中它可能对应10或15个实际的类,如果可能的话会更多。

名称解析也是一个单独的文件。因为它封装了相当多的实现逻辑,在一个大的程序集中,你实际上可以在文件级别来封装它,由于你额外的封装边界,你可以在签名文件级别掩藏大量的细节。这是签名文件的一个用处。基本上,在这种文件中你会看到一个列表,或许是你的文档和某些特性标记,类型,和任何在签名文件掩藏起来没提及的任何东西。

签名文件的另外一个用处是,在你编写框架或函数库的时候,它们能非常好的用来进行函数库的外部设计,只需把这些外部设计代码写到签名文件中,在实现文件中进行函数库的实现。例如,注释,或许有所不同。在签名文件中,你能编写XML的辅助注释,它在函数库和实现文件中是用于构造器的正式帮助,你的注释将说明实现的逻辑。

虽然在两者之间有一点重复,比如公共方法的名称就会重复,但这是机制本身上的基本折衷,它还是可以遵守函数库设计和函数库实现方面的优良方法学。签名文件是这样一个特性,人们经常会想“我为什么非要用它?我不想在另外一个文件重复任何事情!”,而接着,他们会突然就用起它并意识到,在某些特定的应用领域,它实际上可以简化函数库的。

你在很多情况下大概都用到了签名文件,使用的频率介于接口签名和逻辑实现之间,大概有1/3或1/5。有些情况下,根本上几乎没有实现。就像类型定义或其他的东西,在这样的情况下你完全不应该使用签名文件。

   

24. 最后的阶段,或者说稳定F#这个语言的阶段,你们准备好了吗,你们在这样的阶段吗?

这就是最后的设计决策阶段。所有的都完成了。对于我而言,真的不可思议。能发布这个语言,我感觉好极了,我们依旧还有大量的工作要做,要完成所有的规格文档,还要在上面多花时间。在下面几个月内,将最终完成这些,以达到产品化的阶段。

我们还谈论了Power Pack,不过对于我,重要的事情是,这个语言现在已经完工,我们能把这个语言用到所有有趣的事情上,比如正如我刚刚和你说到的服务器端编程工作。当然,重要的事情还有,你曾经编写(大约6个月前)的东西要能和现在的F#代码保持源代码级的兼容。

在开发最新版的F#和调整代码或其他事情的过程,没有做出多大的改变。你现在编写的代码将能永远运行——我们已经在用这个语言了。当然,我们也开始思考下一版本的F#,我们在心中已经想到了一些很好的特性,要最终实现这些特性还需要获得更多的建议,比如更好的错误消息,提高总体体验的方法,以及我们能做到的一些增强。

我们也在开发一些重要特性。现在我还不能完全告诉你。一个重要的事情是,强类型语言是一旦获得数据,就要遵循相应的类型规则,那么编程体验才会顺畅。不过,在类型规则下还是可以有所作为,在F#中进行编码如今也有一些极好的技术。如果你看过《Expert F#》这本书,它马上就要出第二版了,实际上名称会改变。在第二版中,它真正的名称叫做《Art of F# Programming》。我们的出版社在为第二版取名的时候,真的很敏锐。

我们有一个称之为数据构架阅读器设计模式的东西。它实际上是一种在语言的类型规则之下能够获取额外数据,并把数据转为数据构架的一种好方法。它已经被一些人所使用。如果你是F#构架师,或你有志于成为这个语言的牛人,我们推荐你去购买这本书,可以看到这些内容和主题。我们认为,有一些有意思的方法真的可以开启从F#这样的语言的静态类型规则之下获得数据的过程,我们希望能消除这种约束——以静态地获取类型。

   

25. F#使用一些.NET函数库。F#的某些层是否能在.NET的外部来使用?或者说只是用于.NET的F#?

没有,我们没有这样做。F#的核心是提供给F#使用的,它没有设计为在.NET之外的语言中使用。不是特别要阻止你这样做,它的设计不是随意的。现存的函数库主要用于支持F#代码。你购买的一些第三方产品也有用F#实现的,你还是可以用在其他.NET语言当中,不过它比那些通用的.NET组件要特别的多。

   

26. 就是说,常见的场景就是在F#中首先进行一些应用,接着在从其他.NET语言中使用它。

是的。我们看到很多进行应用的人们,一个组件用F#编写,而整个用户界面会用Visual Basic或C#来编写。这是非常常见的方式。我们希望这种方式真正成为一种通用做法,以便实际发布的产品是一个F#组件和几种其他语言开发的组件构成的。我们在F#本身的实现当中也这样做,它包含了大量的F#代码。大部分逻辑是用F#开发,不过在Visual Studio中的属性页是用Visual Basic开发的,也有一个称之为托管打包框架(Managed Package Framework)的C#组件,它整体代码中的一部分也是我们工作的基础。我们就是以这种模式来使用F#。

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT