Haskell:程序员的未来利器(2)--我们真的需要变量吗?

  变量,对于所有的程序员来说都是最最基本的东西,我们似乎从未怀疑过它存在的理由。可是为什么要怀疑呢?所有的语言几乎都是有变量的,变量是我们构造程序的最基本元素,把写程序比作建造一栋大厦的话,变量就是一块块的砖,没有砖怎么能造出大厦呢?等一等,没有砖真的就不能建大厦吗?大厦必须用砖吗?当然不是。可是大厦可以不用砖,那程序没有变量怎么可以呢?可以的,我们也有别的“新材料”(其实并不新)来构造程序,今天我们就来看看这“砖”有什么缺点,我们有什么“新材料”来建大厦。

  既然怀疑变量,我们就要先刨刨变量的根,而且要向祖坟上刨。在语言层面上来说,变量就像一个盒子,里面可以放不同的数据,我们可以把数据拿出来,做一些计算,再放进去。可是扒开这一层,到硬件架构上一看,变量其实就是一个名字与内存地址的绑定,也就是说,变量指向一块内存。再往上刨刨,变量其实就是自动机理论里的状态,在不同的时刻,变量或者说内存里存的数据就代表着现在所在的状态。注意,这里有个很重要的词,“时刻”,这是传统的命令式和OO语言的非常重要的一个元素,所有的代码都是在时间维度上展开的。当程序执行到某个时刻时,程序所有数据就代表了当前的状态。这些不是很好吗?是的,变量对我们来说就像一把刀,当我们用的好的时候,可以得到很高的效率,但是一不小心就会伤到别人或是自己,我们必须把所有代码的执行顺序搞清楚,清清楚楚地告诉计算机应该一步步的做什么,一不小心就可能赋错值、冲掉缓冲区、搞错执行顺序等等,当然,这些可能发生的错误逐渐的在新的语言里受到了限制。但是,随着多核时代的来临,并行计算却很难绕过变量带来的困难。

  并行的问题在于同步与互斥,为什么存在这些问题呢?因为我们共享了数据,当多个线程同时访问数据时就可能产生问题,就必须进行同步,怎么做呢?加锁,于是只要到了有访问共享数据的地方都要小心的加锁解锁,一不小心就可能死锁,这也是程序员畏惧并行的地方。更重要的是,即使我们的程序是正确的,当我们需要更多的线程更多的CPU核心的时候,程序的效率也会不升反降,因为我们将会频繁的加解锁,并行的线程也变得和串行差不多。有更好的方法吗?有人提议将数据库中使用的事务加到语言中,其实,Haskell就是“软件事务内存”(STMSoftware Transaction Memory)的第一个试验田,而且由于Haskell的强大类型系统,没有对语言本身做任何修改,就完美的实现了STM。但是,虽然STM将我们从繁重的加锁解锁劳动中解放了出来,提高了开发效率,也提高了程序的正确率,但执行效率并不比加锁强多少,而且也存在着上面的问题。其实,并行计算已经宣告了共享内存模型的失败,而且,我们的计算机科学家们早就解决了这个问题,那就是使用消息传递,这是在实践中得到检验的。但是,真的是共享惹得祸吗?我认为,我们错怪了共享,我们把变量的问题加到了共享上。是的,如果没有变量,如果我们不能修改已有的数据,那么,尽情的共享吧,不用有任何担心,有多少线程同时读一个数据都不会有问题。

  再举个例子,多核CPU的一个很重要的问题就是Cache的更新与同步,当一个core对本地cache写入时(注意,是修改已有的数据),我们不但要保证新数据与内存中的版本同步,还要同时更新其他核心的cache中的拷贝,并且更新过程中是不能允许这些核心访问这些数据的,IntelAMD的工程师们正拼命的想法解决这个问题,但是问题的根源在那呢?在变量。当我们禁止修改数据时,这个问题突然就不再是问题了。

  可是,没有变量我们怎么写程序?你一定会这样问。如果你有这样的疑问,那说明你被Alan TuringJohn von NewmannJohn Backus等人的理论“误导”了、“毒害”了,知道吗,John Backus因为发明了最早的命令式语言Fortran而荣获图灵奖,但却在图灵奖获奖演讲中否定了自己的成果,为函数式语言大唱赞歌,你可以找来他的演讲论文看看。当你从见到“i=i1”的不解甚至嘲笑到费劲心思、强迫自己的大脑来认为它的存在竟然有意义时,你开始逐步走向深渊了。但是我要告诉你,在haskell的世界里,这个式子确实没有意义。我想,你又一次的不解甚至嘲笑了吧。

  那么,我们怎么写程序呢?函数式语言的理论基础是与图灵机能力相同的Lambda演算,所有的函数式语言都是它的超集,都可以通过类似宏替换的形式化代换方式变成Lambda表达式,而且函数式语言的编译器也都是这么做的。这篇文章里我不想讲太多它的理论,如果有必要我会在以后的文章里讲。今天我就用一个数学的例子,让你有一个直观的了解。比如说要计算x=(12+32)*4-3*(23-7),使用我们的传统方法,会有这样的代码:

a=12

a=a+32

a=a*4

b=23

b=b-7

b=b*3

a=a-b

最终将a保存到x中,实际上,这个计算我们当然不会这样写,但是这确实是我们写程序的方式。但是我们在做数学计算时是这样吗?当然不是,我们会这样(假设我们很笨,这样的计算也要一步步来做):

a=12+32

b=a*4

c=23-7

d=3*c

x=b-d

感觉到不一样了吗?每做一次计算,我们就将结果放到一个新的地方,而不是修改已有的数据,所以这里的abcdx永远不会改变,我们可以放心的使用。再细细观察,我们发现第一段代码中顺序是极其重要的,我们不能将a=a+32a=a*4交换过来,否则就得到错误的结果,也就是说,我们必须清楚的告诉计算机该怎样一步步的进行计算。而第二段中,我们可以把它们理解为“定义”,我们分别定义了abcdx的意义,当我们需要得到x的值时,解释器就可以根据这些定义来进行计算,我们甚至不用关心这些定义的顺序,只要他们都有定义,解释器就可以自己决定先计算谁,在这里,没有顺序,没有时间,没有状态,只有数值。当然,Haskell虽然有解释器,但是一般都是编译的,它可以将我们的代码编译成类似于第一段那样的代码,但是,我们可以肯定的是,Haskell编译器的优化空间是远远大于传统语言的编译器的,因为我们只进行了定义,具体计算都是编译器自己说了算的。

  这就是函数式语言的计算方式。

  当然,你会说,即使这样可以计算,那效率一定很差,光内存的申请就是个问题,的确,函数式语言程序要一直申请内存存放新的数据,同时也有很多计算结果没有用处了成了垃圾,这也就是为什么LISP50多年前就有了垃圾回收。当然,这里面还有很多的效率问题,我会在后面的文章中讨论。但可以肯定的是,现在的Haskell以及一些其他的函数式语言的编译器是非常先进的,它们可以生成效率非常高的代码。而我认为函数式语言的效率问题更多的来自于程序员,因为我们有时会用命令式的思维去写函数式程序。比如,有人批评说Haskell中没有高效的哈希表,可是他不明白哈希表完全是一个基于变量和状态修改的结构,haskell永远不会比得上C,甚至Python,除非它放弃自己的优势特性。有人批评Haskell的快排实现很简单却非常慢,其实快排的算法思想也是基于命令式语言特性的。所以学习haskell更重要的是学习函数式语言的思维方式、设计适合于函数式语言的数据结构和算法的方法。

  我想大家现在应该更深刻的理解变量的优缺点了吧,没有了变量,我们不但可以解决问题,而且能解决(更确切的说是绕过)很多棘手的问题,也能够让程序员更自然的思考问题本身,而不是思考如何实现,从而得到更简洁更优雅的程序。当然,有时候也失去了一些效率,就像所有东西都是对象的说法很可笑一样,函数式语言也并不适合所有问题,我们也要学会使用正确的工具解决正确的问题。但是没有了变量,也就不会有循环,那程序的结构怎么控制?一个优秀的语言自然不会是因为它比别人少了什么东西,而是有什么别人没有的东西,所以我会在以后的文章中介绍haskell所具有的优秀特性.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
看到很多版本都是没书签的,所以就自己添了书签造福一下大家 小小劳动成果,还请尊重,若有错误还请多指教w Abstraction: Programming in Haskell Second Edition Haskell is a purely functional language that allows programmers to rapidly develop clear, concise and correct software. The language has grown in popularity in recent years, both in teaching and in industry. This book is based on the author’s experience of teaching Haskell for more than 20 years. All concepts are explained from first principles and no programming experience isrequired, making this book accessible to a broad spectrum of readers. While Part I focuses on basic concepts, Part II introduces the reader to more advanced topics. This new edition has been extensively updated and expanded to include recent and more advanced features of Haskell, new examples and exercises, selected solutions, and freely downloadable lecture slides and code. The presentation is clean and simple, while also being fully compliant with the latest version of the language, including recent changes concerning applicative, monadic, foldable and traversable types. GRAHAM HUTTON is Professor of Computer Science at the University of Nottingham. He has taught Haskell to thousands of students and received numerous best lecturer awards. Hutton has served as an editor of the Journal of Functional Programming, chair of the Haskell Symposium and the International Conference on Functional Programming, vice-chair of the ACM Special Interest Group on Programming Languages, and he is an ACM Distinguished Scientist.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值