锁定老帖子 主题:失踪的链环
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2006-10-07
Trustno1 写道 庄表伟 写道 很有意思的分析,我也很想直接加入这个讨论,但是沿着T1的消息分派的思路往下谈,一时也不知从何说起,就扯远一点吧。
通常我们做软件开发,往往是最难的事情,就是分解。 其实我并不否认功能分解上的问题.我在文章里面隐约的提到过一点"一般来说,任何具有 Data Abstraction和Message dispatching 能力的系统都能称为OO". 这里的Data Abstraction就是所谓的分解.但是我觉得这样非常感性的探讨没什么目的性,很容易流于朦朦胧胧的形而上学讨论.在就我手边现有的论文来看Data Abstraction或者说功能分解也并不是毫无章法 ,完全靠程序员的自由心证.而是有一定的内在机制的.这些资料给我的一个看法是,Data Abstraction,是一个颇具误导性的词语.我们进行分解往往一个向下取规约的过程,而不是向上抽象的过程.也就是说,语言是一个最基本的模子,我们进行Data Abstraction 或者功能分解,其实是把我们的需求向下规约成语言所有的模式.其实就是一个削足就履的过程.至于细节,恐怕我还无法回答更具体,起码要等我把手边国庆节拉下的Liskov和zilles几篇关于Data Abstraction的论文看掉,才会有更加成型的想法. |
|
返回顶楼 | |
发表时间:2006-10-07
T1提到“静态类型的OO是属于数据导向型的消息分派”,“它的分派机制是与类型严格绑定的.在这个系统里,地址和消息体是互不兼容的.”,“ 但是在现实中地址和消息体可能都是数据”这里有一个其实是存在了2种定义的概念--数据类型。一是:数据类型是数值的一个集合。比如,1.2,0.2,等等构成一个实数的集合,这个集合称之为float的数据类型。
另一个定义是:数据类型是一个数据集合以及附于其上带有某种性质的操作集合。这实际上是一种算术代数。例子么,就是我们自定义的数据类型。 这里再确认一下,我理解的,所谓的静态类型语言,是指在编译阶段进行类型检查的语言。如果一个语言具有一个完备的类型系统,并且能够静态地尽可能多的检出类型不一致的错误(除了类似数组越界等运行时错误),那么这个语言就是一种静态强类型语言。java就是这种(想对的例子,C是静态弱类型语言). 回到T1举的金融卡的例子来。“如果我们仅考虑存放在数据库中的会员信息.那么(姓名,会员卡,性别,年龄,折扣)都是可以进行计算的数据”,这时,数据类型,仅仅使用的是第一种定义,也完全可以通过静态类型检查。 “但是如果要实现这样的需求:"会员卡为金卡的会员折扣加10%”,出现这种要求时,实际数值是需要综合几个数值进行计算得出--这时已只能在运行时才能完全确定。这时,用的就是第二种定义了。在这样的情况下,使用强类型静态语言就会有些麻烦,必须程序员根据具体情况,避开静态类型检查,把类型检查的工作推后到运行时。也就是T1所说的“数据--->类型映射”,把属于第二种定义的情况,转换为第一种定义。这里自然会产生许多手工工作。 魔法与痛苦全在于类型系统的选择,尤其是是否使用静态类型检查。 转头看看语言自身的特性,对于lisp之类的遵循FP编程范式的语言,天生就是为描述抽象代数而设计,应付第二种情况自然更得心应手。但是,有一个问题却是不容忽视的,那就是传统的命令式语言,使用的是与日常生活体验相似的组织方式,所以更容易为学习者接受。而FP系的语言,相对来说,会更加抽象化和数学化,数学思维不强,或者基础不是很好的学习者学习起来,肯定会吃力些,也不容易适应。 所以我挺同意dlee的观点。 |
|
返回顶楼 | |
发表时间:2006-10-07
我觉得静态OO语言在过去承担了两个职责:
1、更好的把复杂度分解到小的单元中去的方式。 2、比面向过程,给程序开发人员提供一个更面向业务概念的编码感觉。这样与业务人员交流的障碍要比面向过程时更顺畅一些。 T1的文章写得很不错。对于静态语言在复杂度分解上花费太多的评述是一针见血,而且对于设计模式的评价也非常得精彩。所以动态OO语言的确是会在未来越来越受欢迎,因为人们可以花更多的时间在做实际的东西,去解决复杂本身,而不是把努力花在分解问题和安排代码上了。希望如此吧。 但是OO给开发带来的交流上的好处是FP不能替代的。FP把注意力完全集中在了算法和解决问题上了。但其实开发中还是有很多时间是耗费在沟通“要解决什么问题,以及问题是什么样”这样的问题上的。OO在这个方面显然是要比面向过程来得成功。而我没有看到纯FP在这个方面能够有什么潜力。 外来的业务一定会变化越来越快以适应市场的需要。这同时会带来问题复杂度本身的提升,和交流难度的提升。所以我们要把关注点同时投注到问题本身和问题沟通上。 |
|
返回顶楼 | |
发表时间:2006-10-07
无明 写道 一是:数据类型是数值的一个集合。比如,1.2,0.2,等等构成一个实数的集合,这个集合称之为float的数据类型。
另一个定义是:数据类型是一个数据集合以及附于其上带有某种性质的操作集合。这实际上是一种算术代数。例子么,就是我们自定义的数据类型。 我并不觉得这是两种数据。实数集,乃至最基本的自然数集都照样可以用函数和操作进行定义.比如说我们可以说实数是由两个整数,一个构造函数,两个选择函数构造而成.自然数可以由一族递归函数进行定义. 具体的可以参看SICP的第一章末尾和第二章开头. |
|
返回顶楼 | |
发表时间:2006-10-07
Trustno1 写道 无明 写道 一是:数据类型是数值的一个集合。比如,1.2,0.2,等等构成一个实数的集合,这个集合称之为float的数据类型。
另一个定义是:数据类型是一个数据集合以及附于其上带有某种性质的操作集合。这实际上是一种算术代数。例子么,就是我们自定义的数据类型。 我并不觉得这是两种数据。实数集,乃至最基本的自然数集都照样可以用函数和操作进行定义.比如说我们可以说实数是由两个整数,一个构造函数,两个选择函数构造而成,具体的可以参看SICP的第一章末尾和第二章开头. 为何不能作为2种定义?自然,按照数学抽象而言,数的一致性显而易见(其实还是有一些特别的)。但是,对于冯诺依曼计算机而言,是有差别的。最简单的差别么,起码指针的偏移量不同。这是具体类型,与抽象类型的差别。对待数据的不同态度,确实是存在的。 不过么,假设java的静态类型检查系统突然关掉,那么,会变成什么样子? |
|
返回顶楼 | |
发表时间:2006-10-08
嘿嘿,磐石T1同学,相当不错阿。建立在FP世界观上,坚定而本质的OO论。
我觉得有一点可以继续阐述一下。FP和命令式语言的一个特别重要的区别,我认为是 data as procedure 和 program as data。虽然说到底都是数据与操作的等价性,但是不同的as得到完全不同的世界观。FP里强调数据是计算,是因为计算是FP的基本封装。但是....x86,或者说图灵机,倾向于认为,程序是一种数据,因此,从c语言发展起来的OO,倾向于使用 函数指针(数据的一种)配合结构实现OO,也就是把行为当作结构的一种特殊数据,其上发展起来的oo带有深刻的数据烙印,也就是类型。而FP上发展起来的OO则必然会是duck typing,也就是以行为区分类型,而不是以类型划分行为。 |
|
返回顶楼 | |
发表时间:2006-10-08
program as data 只是一个大致的说法。要是精确一点,应该说,
program as data provider, program as data selector, program as data structure。 OO 携带数据,主要依靠成员变量。 FP 携带数据,主要依靠 Closure。所有的数据成员都要来自于 function 定义内部,或者是参数,或者是外层局部变量。 比如,pair数据结构的定义(ErLang语法。用Javascript语法可能更容易看懂。只是不太熟悉)。 pair(A, B) -> fun(select_head) -> A; (select_next) -> B end. head(Fun) -> Fun(select_head). next(Fun) -> Fun(select_next). 用法: Pair1 = pair("god", NextElement), Head1 = head(Pair1), %%// god Next1 = next(Pair1), %%// NextElement javascript版本 pair(Head, Next){ return function(selector){ if(selector == "select_Head" ) return Head; else if(selector == "select_Next" ) return Next; } } head(Fun){ return Fun("select_Head" ); } next(Fun){ return Fun("select_Next" ); } 用法: Pair1 = pair("god", NextElement), Head1 = head(Pair1), // god Next1 = next(Pair1), // NextElement 这里面,pair 函数定义就是一个 nested closure。数据源来自于外层函数定义的参数。 这段代码写成 OO 很简单。 Pair { Object head, Next; // getters, setters; } 总体来说,我的感觉,无论是OO,还是FP,数据还是数据,Program还是Program,只是携带数据和提供数据的方式不同。 SICP里面的 Program as Data 说法,应该是为了强调 FP 提供数据方式的不同。 如我们看到,FP提供数据,通常需要更多的嵌套,所以有了更多的屏障。 raimundox 写道 而FP上发展起来的OO则必然会是duck typing,也就是以行为区分类型,而不是以类型划分行为。 这个特征抓得很准确。 另外,行为区分类型,是不是也有点 type inference by behaviour 的意思? |
|
返回顶楼 | |
发表时间:2006-10-08
引用 总体来说,我的感觉,无论是OO,还是FP,数据还是数据,Program还是Program,只是携带数据和提供数据的方式不同。
可以去找一下什么是Church Numerals. 0=lambda (s z): z 1=lambda (s z): s z 2=lambda (s z): s (s z) .......... n=lambda s z . s s^n z 你现在看到的FP都是在冯结构上的模拟,使用简单数据类型是为了运算效率.在正统的lambda 演算里一个整数就等于一个数数操作(counting operation)执行了多少次.就好像是有些不会简单数学的傻子,他们认识的1-10就是等于掰多少个手指头. |
|
返回顶楼 | |
发表时间:2006-10-08
哲学贴. 鉴定完毕。
继续往下,迟早会扯到抽象代数,泛函之类的东西。 引用 而FP上发展起来的OO则必然会是duck typing,也就是以行为区分类型,而不是以类型划分行为。 不懂。很少有人会对着一块石头倾诉衷肠,不论这块石头是不是表现出与众不同的行为。 类型区分行为可以理解,但是为什么要从行为区分类型?怎么感觉是为了类型而类型,难道别人有的东西我也必须得有? |
|
返回顶楼 | |
发表时间:2006-10-08
Trustno1 写道 引用 总体来说,我的感觉,无论是OO,还是FP,数据还是数据,Program还是Program,只是携带数据和提供数据的方式不同。
可以去找一下什么是Church Numerals. 0=lambda (s z): z 1=lambda (s z): s z 2=lambda (s z): s (s z) .......... n=lambda s z . s s^n z 你现在看到的FP都是在冯结构上的模拟,使用简单数据类型是为了运算效率.在正统的lambda 演算里一个整数就等于一个数数操作(counting operation)执行了多少次.就好像是有些不会简单数学的傻子,他们认识的1-10就是等于掰多少个手指头. 这倒也是,lambda 演算里面,整数可以用执行次数来模拟。 SICP里面,我得到的印象是强调 Program 的 Barrier (屏障)作用。 2.1.2 Abstraction Barriers http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-14.html#%_sec_2.1.2 这里讲到了data and program. 2.1.3 What Is Meant by Data? http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-4.html#%_toc_%_sec_2.1.3 But exactly what is meant by data? It is not enough to say ``whatever is implemented by the given selectors and constructors.'' In general, we can think of data as defined by some collection of selectors and constructors, together with specified conditions that these procedures must fulfill in order to be a valid representation. but procedural representations of data will play a central role in our programming repertoire. This style of programming is often called message passing, |
|
返回顶楼 | |