专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »编程综合 » 编程语言的发展趋势及未来方向(3):函数式编程 »正文

编程语言的发展趋势及未来方向(3):函数式编程

来源: 发布时间:星期三, 2010年5月26日 浏览:0次 评论:0
  这是Anders Hejlsberg(不用介绍这是谁了吧)在比利时TechDays 2010所做开场演讲由于最近我在博客上有关语言讨论比较多出于应景也打算将Anders演讲完整地听写出来在上部分中Anders阐述了他眼中声明式编程理念及DSL并演示C#中种内部DSL形式:LINQ在这部分中Anders谈及了声明式编程个重要组成部分:式编程并使用.NET平台上式编程语言F#进行了演示

  如果没有特别介绍说明所有文字都直接翻译自Anders演讲并使用我自己口语习惯表达出来对于Anders口误及反复等情况必要时在译文中自然也会进行忽略为了方便理解我也会将视频中关键部分进行截图而某些代码演示则会直接作为文章内容发表



  有关声明式编程还有部分重要内容那便是式编程式编程已经有很长时间历史了当年LISP便是个式编程语言除了LISP以外我们还有其他许多式编程语言如APL、Haskell、Scheme、ML等等有关式编程在学术界已经有过许多研究了在大约5到10年前许多人开始吸收和整理这些研究内容想要把它们融入更为通用编程语言现在编程语言如C#、Python、Ruby、Scala等等它们都受到了式编程语言影响



  我想在这里先花几分钟时间简单介绍下我眼中式编程语言我发现很多人听说过式编程语言但还不十分清楚它们和普通命令式编程语言究竟有什么区别如今我们在使用命令式编程语言写我们经常会写这样语句x等于x加此时我们大量依赖是状态可变状态或者说变量它们值可以随运行而改变

  可变状态非常强大但随的而来便是叫做“副作用”问题在使用可变状态时则会包含副作用比如你会写个无需参数void思路方法然后它会根据你次数或是在哪个线程上进行产生影响void思路方法会改变内部状态从而影响的后运行效果

  而在式编程中则不会出现这个情况所有状态都是不可变你可以声明个状态但是不能改变这个状态而且由于你无法改变它所以在式编程中不需要变量事实上对式编程讨论更像是数学、公式而不像是语句如果你把x = x + 1这句话交给员看他会说“啊你在增加x值”而如果你把它交给个数学家看他会说“嗯我知道这不是true”



  然而如果你给他看这条语言他会说“啊y等于x加就是把x + 1计算结果交给y你是为这个计算指定了个名字”这时候在研究时就是另种方式了这里y不是个变量它只是x + 1名称它不会改变永远代表了x + 1

  所以在式编程语言中当你写了接受些参数那么当你这个影响只是你传进去参数而你得到也只是计算结果个纯式编程语言中在计算时不会对进行些神奇改变它只会使用你给它参数然后返回结果式编程语言中个void思路方法是没有意义它唯作用只是让你CPU发热而不能给你任何东西也不会有副作用当然现在你可能会说这个CPU发多少热也是个副作用好吧不过我们现在先不讨论这个问题



  这里关键在于你解决问题思路方法和以前大不样了我这里还是用代码来介绍说明问题使用式语言写没有副作用代码就好比在Java或C#中使用final或是readonly成员

  例如这里我们有个Po构造接受x和y还有个MoveBy思路方法可以把个点移动些位置在传统命令式编程中我们会改变Po例子状态这么做在平时可能不会有什么问题但是如果我把个Po对象同时交给3个API使用然后我修改了Po那么如何才能告诉它们状态改变了呢?可能我们可以使用事件blablabla如果我们没有事件那么就会出现那些不愉快副作用了

  那么使用式编程形式写代码Po类还是可以包含状态例如x和y不过它们是readonly化以后就不能改变了 MoveBy思路方法不能改变Po对象它只能创建个新Po对象并返回出来这就是个创建新Po对象不是吗?这样就可以让者来决定是使用新还是旧Po对象但这里不会有产生副作用情况出现

  在式编程里自然不会只有Po对象例如我们会有集合如DictionaryMapList等等它们都是不可变式编程中当我们向个List里添加元素时我们会得到个新List它包含了新增元素但的前List依然存在所以这些数据结构实现方式是有根本性区别它们内部结构会设法让这类操作变尽可能高效

  在式编程中访问状态是十分安全状态不会改变我可以把个Po或List对象交给任意多地方去访问完全不用担心副作用式编程十分容易并行我在运行时不会修改状态因此无论多少线程在运行时都可以观察到正确状态两个完全无关因此它们是并行还是顺序地执行便没有什么区别了我们还可以有延迟计算可以进行Memorization这些都是式编程中十分有趣方面

  你可能会说那么我们为什么不都用这种思路方法来写呢?嗯最终就像我的前说那样我们不能只让CPU发热我们必须要把计算结果表现出来那么我们在屏幕上打印内容时或者把数据写入文件或是Socket时其实就产生了副作用因此真实世界中式编程往往都是把纯粹部分进行隔离或是进行更细致控制事实上也不会有真正纯粹式编程语言它们都会带来副作用或是命令式编程能力但是它们默认是例如在式编程语言中所有东西默认都是不可变你必须做些额外事情才能使用可变状态或是产生危险副作用此时你编程观念便会有所区别了



  我们在自己环境中开发出了这样式编程语言F#已经包含在VS 2010中了F#诞生于微软剑桥研究院由Don Syme提出他在F#上已经工作了5到10年了F#使用了另式编程语言OCaml常见核心部分因此它是个强类型语言并支持些如模式匹配类型推断等现代式编程语言特性在此的上F#又增加了异步工作流度量单位等较为前沿语言功能

  而F#最为重要点可能是在我看来它是第个和工业级框架和工具集如.NET和Visual Studio有深入集成式编程语言F#允许你使用整个.NET框架它和C#也有类似执行期特征例如强类型而且都会生成高效代码等等我想现在应该是展示些F#代码时候了



  首先我想先从F#中我最喜欢特性讲起这是个F#命令行……(打开命令行窗口以及个F#源文件)……F#包含了个交互式命令行这允许你直接输入代码并执行例如输入5……x等于5……然后x……显示出x值是5然后让sqr x等于x乘以x于是我这里定义了个简单名为sqr于是我们就可以计算sqr 5等于25sqr 10等于100

  F#使用方式十分动态但事实上它是个强类型编程语言我们再来看看这里这里我定义了个计算平方和sumSquares它会遍历每个列表中每个元素平方后再把它们相加让我先用命令式方式编写这个再使用方式这样你可以看出其中区别

let sumSquaresI l = 
  let mutable acc = 0 
  for x in l do 
    acc <- acc + sqr x 
  acc


  这里先是命令式代码我们先创建个累加器acc为0然后遍历列表l把平方加到acc中然后最后我返回acc有几件事情值得注意首先为了创建个可变状态我必须显式地使用mutable进行声明在默认情况下这是不可变



  还有这段代码里我没有提供任何类型信息当我把鼠标停留在思路方法上时就会显示sumSquaresI思路方法接受序列作为参数并返回你可能会想是哪里来它是由类型推断而来编译器从这里0发现acc必须是于是它发现这里加号表示两个 相加于是sqr返回是个再接下来blablabla……最终它发现这里到处都是



  如果我把这里修改为浮点数0.0鼠标再停留你就会发现这个接受和返回类型都变成float了所以这里类型推断功能十分强大也十分方便



  现在我可以选择这个让它在命令行里执行然后sumSquaresI提供1到100序列就能得到结果了

let rec sumSquaresF l = 
  match l with 
  |  -> 0 
  | h :: t -> sqr h + sumSquaresF t


  那么现在我们来换风格这里是另种写法可以说是纯实现方式如果你去理解这段代码你会发现有不少数学感觉这里我定义了sumSqauresF输入个l列表然后使用下面模式去匹配l如果它为空则结果为0否则把列表匹配为头部和尾部然后便将头部平方和尾部平方和相加



  你会发现在计算时我不会去改变任何个变量我只是创建新我这里会使用递归就像在数学里我们经常使用递归个公式分解成几个变化形式以此进行递归定义在编程时我们也使用递归做法然后编译器会设法帮我们转化成尾递归或是循环等等

  于是我们便可以执行sumSquaresF也可以得到相同结果当然实际上可能你并不会像的前这样写代码你可能会使用高阶:

let sumSquares l = Seq.sum (Seq.map (fun x -> x * x) l )

  例如这里我只是把x乘以x映射到列表上然后相加这样也可以得到相同结果而且这可能是更典型做法我这里只是想介绍说明这个语言在编程时可能会给你带来完全区别感受虽然它执行期特征和C#比较接近

  这便是有关F#内容

  文章来源:http://blog.zhaojie.me/2010/05/trends-and-future-directions-in-programming-languages-by-anders-3-functional-programming-and-fsharp.html



标签:
0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: