现在的位置: 首页 > 综合 > 正文

关于编程语言

2013年09月06日 ⁄ 综合 ⁄ 共 7035字 ⁄ 字号 评论关闭

关于编程语言的思考

编程语言,就是人类使用的计算机能够理解的语言。它介于人类语言(英语)和机器语言之间。
机器语言已经从二进制代码--》汇编语言--》高级语言。
从人类语言的角度,这种语言必须符合人类的思维习惯和表达方法;从机器语言的角度,它必须精确、没有歧义、可执行(数学化)。
一种理想的编程语言,应该能够用简洁的方式直观、精确地表达人类的丰富思想,富有强大的表现力。同时,能够方便地转换为各种计算机都可以理解的机器语言。
现在的高级语言,都还太复杂,有必要在此基础上再抽象一次,形成自己的语言。
理想的编程语言的特性:
1-简洁:符号特别少,语法规则特别简单,代码特别短;
2-容易:易于安装,易于编写,易于调试/测试;
3-跨平台:可以在任何硬件和操作系统平台上运行;
4-高度抽象:可以解决任何问题(主流语言);只要把问题描述清楚,解法也就出来了(快速开发原型);
5-逻辑严谨:使产生bug的可能性降到最低;
6-灵活:便于修改,支持持续演进/敏捷开发;
7-提供出色的性能分析器,发现运行瓶颈以便优化;
8-有大量优秀的范例和函数库可以使用:自己只用写很少的代码就可以解决大部分常见问题;
9-开放源代码:可以随意修改内核;
10-可以方便地同操作系统、其他语言开发的程序对话;
11-代码复用:易于编写/维护大型项目(工业级);
12-有其他人使用,便于交流;

编程语言的选择

现代的高级语言有很多,很多主流语言都具备上述部分优点,但无法泛泛地说某种语言是最好的,因为语言的特点都是面向特定环境或问题的。
首先,我要考虑到硬件平台。我面对的硬件平台相当广泛:ARM嵌入式开发板-手机-平板电脑-PC机-服务器...
未来的任何硬件平台都可以运行LINUX系统(而且发展方向是Ubuntu)。所以编程语言要做到硬件和操作系统的跨平台。
WEB是目前最好的跨平台方案。任何平台都可以运行WEB程序,而且用WEB技术既可以开发网站,也可以开发桌面程序(其界面一点不输于专业工具开发的桌面程序)。所以,我的主要工作环境是WEB编程。在WEB环境中,javascript是第一大语言,也是拥有最多现成代码、库、测试用例、开发环境等等的工业语言。所以,我选择javascript作为基本语言。但是,javacript存在一些缺陷(如默认全局变量、语法的不够简练、缺乏类的继承、不支持Unicode、缺少语句块支持等)。这可以通过其他一些语言和工具来弥补。

Scheme可以处理复杂的算法问题;作为函数式语言的翘楚,LISP两大方言之一,有强大的算法能力。
1.函数即数据。所有函数均有返回值,所以函数也是一种数据类型,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。典型的就是回调函数的使用。函数编程支持函数作为第一类对象,有时称为 闭包或者 仿函数(functor)对象。实质上,闭包是起函数的作用并可以像对象一样操作的对象。在面向对象编程中,我们把对象传来传去,那在函数式编程中,我们要做的是把函数传来传去,而这个,说成术语,我们把他叫做高阶函数。。高阶函数可以用另一个函数(间接地,用一个表达式) 作为其输入参数,在某些情况下,它甚至返回一个函数作为其输出参数。这两种结构结合在一起使得可以用优雅的方式进行模块化编程,这是使用
FP 的最大好处。
在函数式编程中,函数是基本单位,是第一型,他几乎被用作一切,包括最简单的计算,甚至连变量都被计算所取代。在函数式编程中,变量只是一个名称,而不是一个存储单元,这是函数式编程与传统的命令式编程最典型的不同之处。
2.只用"表达式",不用"语句"
"表达式"(expression)是一个单纯的运算过程,总是有返回值;"语句"(statement)是执行某种操作,没有返回值。函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。
原因是函数式编程的开发动机,一开始就是为了处理运算(computation),不考虑系统的读写(I/O)。"语句"属于对系统的读写操作,所以就被排斥在外。
当然,实际应用中,不做I/O是不可能的。因此,编程过程中,函数式编程只要求把I/O限制到最小,不要有不必要的读写行为,保持计算过程的单纯性。
3. 没有"副作用"和别名
所谓"副作用"(side effect),指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。
别名是同一个对象有两个以上的名字,如果对一个对象的修改可能由于“副作用”而修改了另一“不同的”对象,而后者其实是前者的别名,程序里就容易出现错误。
函数式编程强调没有"副作用",意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值。函数式编程没有副作用,只要保证接口不变,内部实现是外部无关的。所以,可以在运行状态下直接升级代码,不需要重启,也不需要停机。
4. 不修改状态
上一点已经提到,函数式编程只是返回新的值,不修改系统变量。因此,不修改变量(不用任何赋值语句),也是它的一个重要特点。在其他类型的语言中,变量往往用来保存"状态"(state)。不修改变量,意味着状态不能保存在变量中。函数式编程使用参数保存状态,最好的例子就是递归。函数式编程不依赖、也不会改变外界的状态,只要给定输入参数,返回的结果必定相同。因此,每一个函数都可以被看做独立单元,很有利于进行单元测试(unit testing)和除错(debugging),以及模块化组合。函数式编程不需要考虑"死锁"(deadlock),因为它不修改变量,所以根本不存在"锁"线程的问题。不必担心一个线程的数据,被另一个线程修改,所以可以很放心地把工作分摊到多个线程,部署"并发编程"(concurrency)。
5.大量使用递归
递归是函数式编程的一个重要的概念,循环可以没有,但是递归对于函数式编程却是不可或缺的。递归充分地发挥了函数的威力,也解决了函数式编程无状态的问题。
递归其实就是将大问题无限地分解,直到问题足够小。而递归与循环在编程模型和思维模型上最大的区别则在于:循环是在描述我们该如何地去解决问题。递归是在描述这个问题的定义。优化了尾递归,支持惰性计算。除了高阶函数和仿函数(或闭包)的概念,FP 还引入了惰性计算的概念。在惰性计算中,表达式不是在绑定到变量时立即计算,而是在求值程序需要产生表达式的值时进行计算。延迟的计算使您可以编写可能潜在地生成无穷输出的函数。因为不会计算多于程序的其余部分所需要的值,所以不需要担心由无穷计算所导致的 out-of-memory 错误。一个惰性计算的例子是生成无穷
Fibonacci 列表的函数,但是对 第 n 个Fibonacci 数的计算相当于只是从可能的无穷列表中提取一项。
5. 引用透明
引用透明(Referential transparency),指的是函数的运行不依赖于外部变量或"状态",只依赖于输入的参数,任何时候只要参数相同,引用函数所得到的返回值总是相同的。有了前面的第三点和第四点,这点是很显然的。其他类型的语言,函数的返回值往往与系统状态有关,不同的状态之下,返回值是不一样的。这就叫"引用不透明",很不利于观察和理解程序的行为。
6.接近自然语言的写法
接近自然语言,易于理解
函数式编程的自由度很高,可以写出很接近自然语言的代码。
前文曾经将表达式(1 + 2) * 3 - 4,写成函数式语言:
  subtract(multiply(add(1,2), 3), 4)
对它进行变形,不难得到另一种写法:
  add(1,2).multiply(3).subtract(4)
7.变量的动态类型
所有变量实际上都是指针,所指向的值有类型之分,而变量本身没有。复制变量就等于复制指针。比较两个变量,只要看它们的指针是否一样就可以了。
8. 代码使用符号和常量组成的树型表示法
程序本身也是JSON结构,可以通过JSON传递,也可以通过JSON彼此通讯。通过嵌套的缩进体现树型结构。
9. 无论什么时候,整个程度都是可用的。

也就是不区分读取期、编译期和运行期。随时可以运行和修改。

Scheme教学平台http://www.htdp.org/(配套Racket开发环境),其中涉及不少常见算法,更多算法和库可以在PlantT或其他Scheme库中找到。

Coffeescript 
可实时解释为JS的JS变种语言。提供了完善的CLASS类继承功能,和强大数组功能。和jQuery结合功能更为强大。适合于面向对象开发。

jQuery
Jquery使用最广泛的Javascript库。jQuery使用户能更方便地处理HTML documents(DOM)、events、实现动画效果,并且方便地为网站提供AJAX交互。用户只需要面向jQuery的API编程即可,不用再使用原生JS。

HTML5&CSS3
页面布局语言及其样式表,用简易的标签支持一些音视频/动画等,

NoSQL
更加灵活的数据库,以MongoDB和其嵌入式变种EJDB为代表。它们保存的不是表,而是文档。这几个数据库所谓的“文档”,其实就是JSON文档,这是一种标准化的数据交换格式,它也是JS的标准对象表现格式。所以在不用ORM的情况下实现数据的“对象化”。同时,NoSQL数据库不用预先定义数据库结构,可随时改变“表”结构。

NodeJS
C++开发的JS框架,同时提供了服务器端的浏览器解释、操作系统接口和高性能WEB框架。

由于JS流行,很多语言都可以编译为JS,在浏览器中运行了。所以,JS也成为各种语言的“虚拟机”。未来的发展趋势是:在JS平台上跑各种工具语言。

我的编程平台

搭积木的方式,从低层到高层,围绕javascript使用不同的工具。
前端:HTML5+CSS3实现基本图形界面,express作为WEB框架,bootstrap实现统一控件,jQuery库实现交互效果,highCharts等图表库实现图表, WebGL实现3D效果。。。。
后端:JS写程序框架,嵌入EJDB数据库,通过nodeJS的API进行系统交互和C/C++扩展,scheme完成复杂算法,PhoneGap调用手机资源。
node-webkit:提供了chrome的webkit(google的HTML+javascript引擎)和node.js环境
操作系统:Ubuntu/FSD(可以使裁剪的各种Linux版本)

编程方式

尽可能利用别人的现成代码,是最有效率的编程方式。所以,我的主要工作不是“写”程序,而是“改程序”。
1.写项目需求说明。
工具:WPS(编辑文档),dropbox保存和分享文件;
2.写项目设计方案
工具:WPS(编辑文档),StarUML画系统设计图,dropbox保存和分享文件。
3.画界面
工具:直接用sublimeText修改标准化的bootstrap模板,在chrome中预览。做好后打包到node-webkit中。
4.模块化开发
定义接口
编写后台代码
    写程序框架    ----sublimeText:CS
    确定数据结构:抽象出库、函数、对象等;----sublimeText: CS
    查找有否可用的代码资源;
    给每个小模块写算法:先用伪代码,再用真实代码。----sublimeText: CS
    代码检查  
编写测试用例和示例数据库  ----sublimeText: EJDB
单元测试 Nodeunit
5.集成测试(web模式)
代码集成;
编写测试用例;
测试:
6.打包
整理代码,去除注释;
写帮助文档;
打包到node-webkit中
写配置文件,按平台编译。
体验测试。

敏捷原则:尽快做出原型,不断迭代修改。
抽象三原则:
唯一性原则:
系统的每一个功能都应该有唯一的实现。也就是说,如果多次遇到同样的问题,就应该抽象出一个共同的解决方法,不要重复开发同样的功能。
简单化原则:
除了最核心的功能,其他功能一概不要部署,这样可以大大加快开发。
第三次原则:
第一次用到某个功能时,你写一个特定的解决方法;第二次又用到的时候,你拷贝上一次的代码;第三次出现的时候,你才着手"抽象化",写出通用的解决方法。这样做有几个理由:(1)省事。如果一种功能只有一到两个地方会用到,就不需要在"抽象化"上面耗费时间了。(2)容易发现模式。"抽象化"需要找到问题的模式,问题出现的场合越多,就越容易看出模式,从而可以更准确地"抽象化"。

健壮性

逻辑严谨,避免BUG。所谓BUG,有两层含义:1.软件的运行结果没有达到设计目的;2.在运行中发生错误(无法运行/死机/计算错误/内存溢出等)。这里主要指低条。
软件出现Bug的原因有:
(1)程序不合乎语法--可以通过语法检查避免;
(2)对输入的边界情况处理不到位--对每个输入进行限定;
(3)对各种流程分支考虑不全面--对所有分支语句都有else托底;
(4)程序运行中可能发生的异常结果--尽量使用久经考验的函数库;
(5)处理的对象类型不对--尽量使用弱类型语言;
(6)耗尽了计算机的资源--对于递归和大数据要考虑内存;
为避免BUG,采用测试驱动的编程方法。一开始就编写测试用例。测试用例在实际代码之前就被写出来了。代码只有在通过测试的时候才被认为完成了。
另一个措施是在容易出错的地方加上报错输出。

编程语言的基本内容

任何语言必须包括如下基本内容:
1.基本的表达形式:能够表达基本的数据和基本的过程。
2.抽象的方法:通过它们可以为复合对象命名,并将它们当作单元去操作。
3.组合的方法:如何将较简单的东西构造成复杂的东西。

抽象本质
在面向对象编程中,我们说,类是现实事物的一种抽象表示。那么抽象的最大作用在我看来就在于抽象事物的重用性,一个事物越具体,那么他的可重用性就越低,因此,我们再打造可重用性代码,类,类库时,其实在做的本质工作就在于提高代码的抽象性。而再往大了说开来,程序员做的工作,就是把一系列过程抽象开来,反映成一个通用过程,然后用代码表示出来。
在面向对象中,我们把事物抽象。而在函数式编程中,我们则是在将函数方法抽象,函数一样是可重用,可置换的抽象单位。那么我们说函数式编程的抽象本质则是将函数也作为一个抽象单位,而反映成代码形式,则是高阶函数。

第1 基本的表达形式
基本数据:
(1)数字:不区分数字的类型
(2)字符串:一个或多个字符组成,使计算机可以处理人类语言。
(3)布尔值:true 和 false
(4)空值:null

基本符号:
数学计算符号:可以将数字连接在一起,组成表达式。(其实也是基本过程,只不过由解释器实现了)
逻辑符号:与 或 非 
分割符号:()[]{}''"",

基本表达式(基本的过程):
由基本数据和基本符号组成;
任何表达式都有值;

基本控制流程:
顺序结构:一个表达式接一个表达式,顺序执行。
分支结构:根据条件的值判断执行哪些后续表达式,计算机具有了智能。
循环结构:重复执行表达式,计算机具有了强大的能力。

命名与环境:
可以给任何对象起一个名字;
可以用=给对象赋值,如Pi = 3.14159265
环境:保持名称-值关联关系的存储空间。命名只在某个环境中有效。离开这个环境将被释放掉。

第2 过程的抽象
给一个基本的过程起个名字,这就成为一个函数。函数应该隐藏细节,使函数的调用者象使用一个黑箱一样不需要知道它是如何实现的。这样,人们就可以在更高的抽象层次上工作。
函数的嵌套应用,可以构成复杂的过程(高阶函数和块结构)。这可以表示为树型。到这里,计算机还只具有计算能力。
函数的形式参数只具有局部作用域。
函数的嵌套调用也包括它自己,就是递归。
函数可以作为另一个函数的返回值。

第3 数据抽象
复合数据,是把简单的数据(数字、字符串等)“粘合”在一起形成的可以作为一个整体使用的对象。甚至过程也可以用这种方法粘合在一起。这进一步模糊了过程和数据之间的界限。
数据抽象,是把数据的不断复合再复合,将数据的组成细节和数据的使用分离开(抽象屏障),使人们可以处理复杂的对象。
复合数据的一个关键工具是闭包。
复合数据对象能够成为以混合与匹配的方式组合程序模块的方便界面。

第4 层次设计--基本的组合方法
在复杂系统的工程中广泛使用分层的设计方法。在分层设计中,每个层次上所采用的语言都提供了一些基本元素、组合手段,还有对该层次中适当细节做抽象的手段。例如,不同的原子组成不同的分子,不同的分子组成不同的蛋白质,不同的蛋白质组成不同的细胞,不同的细胞组成不同的组织,不同的组织组成不同的器官,不同的器官组成循环、消化、呼吸等不同的系统,最后构成人。
至于组合哪些对象,这要看现实中的实体可以模型化为哪些对象。

我的工具集

 编辑器sublime text
 同步工具:dropbox --参见https://www.dropbox.com/的说明文档
基础语言:Javascript(JS)   --参见http://www.w3school.com.cn/js/index.asp
框架语言:Coffeescript(CS)
算法语言:Scheme
 正则表达式

数据库:EJDB和MongoDB
后端解释器:NodeJS
测试工具:NodeUnit

前端基础:HTML5+CSS3
统一界面:Bootstrap
前端利器:jQuery
图表库:HighCharts
图像库:WebGL等

打包工具:node-webkit
移动开发工具:phoneGap

抱歉!评论已关闭.