[关键字]
goto, goto with parameters, stack, stackless, continuation
[参考资料]
http://c2.com/cgi/wiki?ContinuationsAreGotos
http://c2.com/cgi/wiki?ContinuationsInCee
http://c2.com/cgi/wiki?SingleUseContinuation
[正文]
这是一个不常见控制流的系列,把参考资料优先放在头部也是不常见的。
最早我们接触编程语言里的的goto,然后我们被告知不要使用goto,使用goto会破坏结构化程序设计。我记得第一次学计算数学的《计算线性代数》、《数值分析》等计算数学入门课程时,我们书上很多算法都是用为代码形式给出,这类算法很多都是迭代型的,只有迭代收敛或超时超出迭代次数就退出。用编程语言的写法,如果没有提供循环这种特性,就只能用1、1、label+goto是实现迭代;2、递归做法。所以递归当然可以完成迭代的任务,这是另一回事。所以goto我们是很熟悉的。实际上if-else-then、while、for、call-function都可以用goto做到。只是由于直接使用goto会导致代码及其难读和不可维护,所以才出现结构程序设计。但即使如此,大部分语言都保留了goto的能力以备不时之需。
我觉得非计算机系的人学语言挺亏的,就像非数学系的人学高等数学很亏一样(当然后面可以弥补,但如果一开始就从正确的入口进去,何必走弯路?)。之所以这么说,是因为数学分析会先把极限的概念、episode-xigema收敛证明法讲解的非常透彻,然后基于这个坚实的概念再往上学微积分,这样学微积分,如果你想剖丁解牛,你就有机会分解下层抽象去做推理,这也解释了另一个软件术语的含义「抽象泄漏法则」,你不得不透过抽象背后的逻辑去理解事物的本质。编程也是这样的,C语言的函数调用直接从汇编的层面看,函数调用栈是一个非常重要的概念,这样能理解函数调用的栈顶保存,参数传递顺序,函数返回前的清空函数栈、恢复上层函数栈顶等动作。从而对函数调用开销有直观的理解,并且也容易去区分和理解栈上变量、堆上变量之间生命周期的区别,并且对寄存器有直观的理解。
<未完待续,这节不好写,慢慢来>
2014年3月10日星期一
2014年3月8日星期六
探索那些不常见的控制流(2)
尾(巴)递归,尾调用优化,尾递归优化
tailrecursion, tailcall optimization and tailreursion eliminate
最早学scheme的时候就玩过尾递归(tailrecursion),不过当时只是在形式上玩了下,也大概理解尾递归可以让编译器重用函数调用栈,而不会导致函数调用栈溢出发生,同时模糊的说这种写法可以和迭代的效率相当。我们一群人学scheme的时候,只是皮毛的把SICP的前2章的内容和题目看掉、做掉。那段时间我狂看C++的那些书籍,学STL我就直接硬着头皮大致看掉《STL源码剖析》(我才发现要学一个东西未必要按部就班从Prime开始,直接跳过Prime书籍直接看深入一点的书籍也是大有好处的,不用先非常熟悉使用,过了很久之后才想起来去看下源码,才发现之前很多用法实际上多绕了很多弯路,MFC没用过,但我看过《MFC深入浅出》前几章,大概知道那些繁杂的要点在哪,这样就不会心里有惧怕感。);学模板我就看了《The C++ Template》这书,这样就对那些特化、偏特化、typename,template template class,编译时多态(元编程,MetaProgram)等概念有比Prime系统性的一些了解,后面还粗略看了《Morden C++ Template》,知道boost和loki;学C++运行时多态,我看了《Internal C++ Object Model》,这样就知道了class对象的内存分布,也就是虚函数表是最重要的,对象的构造、析构等也与内存分布息息相关,而且虽然不学COM,但知道COM要做ABI也是要知道C++的内存分布的,《COM本质论》前几章也在讲这个。SICP的习题都是一环扣一环,后面的习题直接给予前面的习题来继续做,这样我印象很深的是,抽象是如何被一步步封装起来的,对于每道习题,只要之前习题已经搭建的那些抽象(函数)是坚实的,就可以被用来组合新的抽象,这样我对于「任何软件问题都可以通过添加抽象层解决」这句话就有深入一点的理解,并且印象深刻。scheme由于概念简洁,function是一等公民,所以你会一直专注在解决问题本上上,而不用像C++那样一个又一个特性让你话费大把时间去学习和积累。函数式编程一些重要的概念:惰性求值、无副作用、无状态、不变性等基本概念都深入到我脑子里,以后我用其他语言的时候会不断重新发现这些概念。
想起来之前的那些事就顺便多写了这些,最近开始系统性重新学习和发现那些以前有些清晰有些模糊的概念:tailrecursion, tailcalloptimization, tailrecursioneliminate, continuation passing style, call-with-current-continuation,closure,coroutine,concept, constraint template arguments, lambda, recursion function等等。我想一边把这些编程语言相关的外在概念都梳理一遍,同时系统性学习编译原理、类型理论,再结合实战研究编程语言的实现,希望把这个角落清扫一遍。
恩,本系列以小步迭代方式进行。本节实际上是从下面页面的代码片段拿过来注释了下尾巴递归的概念。
http://c2.com/cgi/wiki?TailRecursion
#include <stdio.h>
#include <stdlib.h>
/**
*非尾巴递归,return的时候需要做调用自己和一次乘法
*/
int factorial0(int n) {
if (n == 0) return 1;
return n * factorial0(n - 1);
}
/**
*尾巴递归,return的时候只做一件事:递归调用自己
*/
int factorialimpl(int n, int accumulator) {
if (n == 0) return accumulator;
return factorialimpl(n - 1, n * accumulator);
}
int factorial1(int n) {
return factorialimpl(n, 1);
}
/**
*如果编译器能够识别并为尾巴递归做优化,则尾巴递归
*等价于如下代码,不需要反复进入和退出嵌套的调用栈
*/
int factorial2(int n, int accumulator) {
beginning:
if (n == 0) return accumulator;
else {
accumulator *= n;
n -= 1;
goto beginning;
}
}
/**
*因此,尾巴递归的性能将和下面的迭代等价
*/
int factorial3(int n, int accumulator) {
while (n != 0) {
accumulator *= n;
n -= 1;
}
return accumulator;
}
/**
*这就是尾巴递归的故事,用C语言描述
*/
int main(){
return 0;
}
上面的c代码演示了什么是尾巴递归,尾巴递归必须在函数返回前只做一件事,那就是递归调用自己。尾巴递归调用的重点在于递归调用返回到上一层调用栈的时候,上一层调用栈并不需要利用这个返回值做点什么事(否则,上层调用栈就必须保留栈上下文),而是直接返回给上上层调用栈。那么对于一定要对递归调用结果「做点什么事」的需求来说,就必须把要参与「做点什么事」的那些数据和函数传递给下层调用栈,比如这个例子里通过accumulator把结果传递给递归调用函数。
那么尾巴递归调用就保证了在尾巴递归的时候不需要保留上层函数调用栈上下文。所以如果编译器能识别尾巴递归调用,则可以对尾巴递归调用做「tailrecursion eliminate」,也就是例中的示意代码。消除了递归调用,从而把递归变成迭代。但这个前提是编译器会帮你做这件事,否则就算你写的代码是尾巴递归调用,但编译器不做「tailrecursion eliminate」的话,则没有这些福利。scheme、lua等语言都有对尾巴递归调用做消除。
进一步的,如果一个函数调用虽然不是经典的「tailrecursion」,但是在return之前只做一件事,就是调用某个其他子过程。则上层函数调用栈也不需要保存,则这个时候编译器可以做「tailcall optimization」,也就是尾调用优化。我们来下下例子:
http://c2.com/cgi/wiki?TailCallOptimization
/**
*进一步的,尾调用优化
*/
int bar(int a){
printf("bar called with arg %d\n", a);
return a * a;
}
int foo(int b){
return bar(b * b);//函数返回前只做一件事,调用只过程,并且把b*b的结果传入到子过程
}
/**
*然而,这个例子里,foo的栈如果被优化掉,则a的生命周期
*被破坏,所以用栈上变量a是不安全的。
*/
int bar(int *b){
return *b * 10;
}
int foo(){
int a = 5;
return bar(&a);
}
tailrecursion, tailcall optimization and tailreursion eliminate
最早学scheme的时候就玩过尾递归(tailrecursion),不过当时只是在形式上玩了下,也大概理解尾递归可以让编译器重用函数调用栈,而不会导致函数调用栈溢出发生,同时模糊的说这种写法可以和迭代的效率相当。我们一群人学scheme的时候,只是皮毛的把SICP的前2章的内容和题目看掉、做掉。那段时间我狂看C++的那些书籍,学STL我就直接硬着头皮大致看掉《STL源码剖析》(我才发现要学一个东西未必要按部就班从Prime开始,直接跳过Prime书籍直接看深入一点的书籍也是大有好处的,不用先非常熟悉使用,过了很久之后才想起来去看下源码,才发现之前很多用法实际上多绕了很多弯路,MFC没用过,但我看过《MFC深入浅出》前几章,大概知道那些繁杂的要点在哪,这样就不会心里有惧怕感。);学模板我就看了《The C++ Template》这书,这样就对那些特化、偏特化、typename,template template class,编译时多态(元编程,MetaProgram)等概念有比Prime系统性的一些了解,后面还粗略看了《Morden C++ Template》,知道boost和loki;学C++运行时多态,我看了《Internal C++ Object Model》,这样就知道了class对象的内存分布,也就是虚函数表是最重要的,对象的构造、析构等也与内存分布息息相关,而且虽然不学COM,但知道COM要做ABI也是要知道C++的内存分布的,《COM本质论》前几章也在讲这个。SICP的习题都是一环扣一环,后面的习题直接给予前面的习题来继续做,这样我印象很深的是,抽象是如何被一步步封装起来的,对于每道习题,只要之前习题已经搭建的那些抽象(函数)是坚实的,就可以被用来组合新的抽象,这样我对于「任何软件问题都可以通过添加抽象层解决」这句话就有深入一点的理解,并且印象深刻。scheme由于概念简洁,function是一等公民,所以你会一直专注在解决问题本上上,而不用像C++那样一个又一个特性让你话费大把时间去学习和积累。函数式编程一些重要的概念:惰性求值、无副作用、无状态、不变性等基本概念都深入到我脑子里,以后我用其他语言的时候会不断重新发现这些概念。
想起来之前的那些事就顺便多写了这些,最近开始系统性重新学习和发现那些以前有些清晰有些模糊的概念:tailrecursion, tailcalloptimization, tailrecursioneliminate, continuation passing style, call-with-current-continuation,closure,coroutine,concept, constraint template arguments, lambda, recursion function等等。我想一边把这些编程语言相关的外在概念都梳理一遍,同时系统性学习编译原理、类型理论,再结合实战研究编程语言的实现,希望把这个角落清扫一遍。
恩,本系列以小步迭代方式进行。本节实际上是从下面页面的代码片段拿过来注释了下尾巴递归的概念。
http://c2.com/cgi/wiki?TailRecursion
#include <stdio.h>
#include <stdlib.h>
/**
*非尾巴递归,return的时候需要做调用自己和一次乘法
*/
int factorial0(int n) {
if (n == 0) return 1;
return n * factorial0(n - 1);
}
/**
*尾巴递归,return的时候只做一件事:递归调用自己
*/
int factorialimpl(int n, int accumulator) {
if (n == 0) return accumulator;
return factorialimpl(n - 1, n * accumulator);
}
int factorial1(int n) {
return factorialimpl(n, 1);
}
/**
*如果编译器能够识别并为尾巴递归做优化,则尾巴递归
*等价于如下代码,不需要反复进入和退出嵌套的调用栈
*/
int factorial2(int n, int accumulator) {
beginning:
if (n == 0) return accumulator;
else {
accumulator *= n;
n -= 1;
goto beginning;
}
}
/**
*因此,尾巴递归的性能将和下面的迭代等价
*/
int factorial3(int n, int accumulator) {
while (n != 0) {
accumulator *= n;
n -= 1;
}
return accumulator;
}
/**
*这就是尾巴递归的故事,用C语言描述
*/
int main(){
return 0;
}
上面的c代码演示了什么是尾巴递归,尾巴递归必须在函数返回前只做一件事,那就是递归调用自己。尾巴递归调用的重点在于递归调用返回到上一层调用栈的时候,上一层调用栈并不需要利用这个返回值做点什么事(否则,上层调用栈就必须保留栈上下文),而是直接返回给上上层调用栈。那么对于一定要对递归调用结果「做点什么事」的需求来说,就必须把要参与「做点什么事」的那些数据和函数传递给下层调用栈,比如这个例子里通过accumulator把结果传递给递归调用函数。
那么尾巴递归调用就保证了在尾巴递归的时候不需要保留上层函数调用栈上下文。所以如果编译器能识别尾巴递归调用,则可以对尾巴递归调用做「tailrecursion eliminate」,也就是例中的示意代码。消除了递归调用,从而把递归变成迭代。但这个前提是编译器会帮你做这件事,否则就算你写的代码是尾巴递归调用,但编译器不做「tailrecursion eliminate」的话,则没有这些福利。scheme、lua等语言都有对尾巴递归调用做消除。
进一步的,如果一个函数调用虽然不是经典的「tailrecursion」,但是在return之前只做一件事,就是调用某个其他子过程。则上层函数调用栈也不需要保存,则这个时候编译器可以做「tailcall optimization」,也就是尾调用优化。我们来下下例子:
http://c2.com/cgi/wiki?TailCallOptimization
/**
*进一步的,尾调用优化
*/
int bar(int a){
printf("bar called with arg %d\n", a);
return a * a;
}
int foo(int b){
return bar(b * b);//函数返回前只做一件事,调用只过程,并且把b*b的结果传入到子过程
}
/**
*然而,这个例子里,foo的栈如果被优化掉,则a的生命周期
*被破坏,所以用栈上变量a是不安全的。
*/
int bar(int *b){
return *b * 10;
}
int foo(){
int a = 5;
return bar(&a);
}
2014年3月2日星期日
探索那些不常见的控制流(1)
http://coolshell.cn/articles/10975.html
这篇文章介绍了一个“蝇量级” C 语言协程库的实现。
里面使用宏封装了下,不过我不喜欢宏,觉得宏把简单的东西隐藏而不可见。因为我并不会真正直接用这些宏,只是为了搞清楚如何在C里实现yiled,去掉宏之后,我们可以很清晰的看懂代码的结构和流程。
下面的代码从http://www.chiark.greenend.org.uk/~sgtatham/coroutine.h解析:
#include <stdio.h>
#include <stdlib.h>
/**
*单线程coroutine,不可重入
*/
int function(void){
static int i,state = 0;
switch(state){
case 0:
for(i=0;i<10;i++){
state = 1;
return i;
case 1:;
}
}
}
/**
*多线程coroutine,可重入
*/
typedef void* ccr_context_handle;
typedef struct tag_ccr_context{
int state;
int i;
}ccr_context;
int ascending(ccr_context_handle* ccr_context_handle_pointer) {
ccr_context* this = (ccr_context*)*ccr_context_handle_pointer;
if(!this){
this = malloc(sizeof(ccr_context));
*ccr_context_handle_pointer = this;
this->state = 0;
}
if(this){
switch(this->state){
case 0:;
for (this->i=0;this->i<10; this->i++) {
this->state = 1;
return this->i;
case 1:;
}
}
free(*ccr_context_handle_pointer);
*ccr_context_handle_pointer = 0;
return -1;
}
}
/**
*C测试代码
*/
int main(){
printf("\n");
int i=0;
for(i=0;i<10;i++){
printf("%d",function());
}
printf("\n");
ccr_context_handle handle = 0;
do {
int ret = ascending(&handle);
if(ret!=-1){
printf("%d",ret);
}
}while(handle);
printf("\n");
return 0;
}
当我继续搜索,上述代码在这个页面出现:
http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
这个页面里描述了在C语言里做coroutine。以及一个典型的生产者消费者模型。在C里面做协程并不轻松,底下更本质的原因是因为C语言里对continuation的支持很低阶,什么是continuation我们会在后面的节里给出。
这篇文章介绍了一个“蝇量级” C 语言协程库的实现。
里面使用宏封装了下,不过我不喜欢宏,觉得宏把简单的东西隐藏而不可见。因为我并不会真正直接用这些宏,只是为了搞清楚如何在C里实现yiled,去掉宏之后,我们可以很清晰的看懂代码的结构和流程。
下面的代码从http://www.chiark.greenend.org.uk/~sgtatham/coroutine.h解析:
#include <stdio.h>
#include <stdlib.h>
/**
*单线程coroutine,不可重入
*/
int function(void){
static int i,state = 0;
switch(state){
case 0:
for(i=0;i<10;i++){
state = 1;
return i;
case 1:;
}
}
}
/**
*多线程coroutine,可重入
*/
typedef void* ccr_context_handle;
typedef struct tag_ccr_context{
int state;
int i;
}ccr_context;
int ascending(ccr_context_handle* ccr_context_handle_pointer) {
ccr_context* this = (ccr_context*)*ccr_context_handle_pointer;
if(!this){
this = malloc(sizeof(ccr_context));
*ccr_context_handle_pointer = this;
this->state = 0;
}
if(this){
switch(this->state){
case 0:;
for (this->i=0;this->i<10; this->i++) {
this->state = 1;
return this->i;
case 1:;
}
}
free(*ccr_context_handle_pointer);
*ccr_context_handle_pointer = 0;
return -1;
}
}
/**
*C测试代码
*/
int main(){
printf("\n");
int i=0;
for(i=0;i<10;i++){
printf("%d",function());
}
printf("\n");
ccr_context_handle handle = 0;
do {
int ret = ascending(&handle);
if(ret!=-1){
printf("%d",ret);
}
}while(handle);
printf("\n");
return 0;
}
当我继续搜索,上述代码在这个页面出现:
http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
这个页面里描述了在C语言里做coroutine。以及一个典型的生产者消费者模型。在C里面做协程并不轻松,底下更本质的原因是因为C语言里对continuation的支持很低阶,什么是continuation我们会在后面的节里给出。
2014年2月10日星期一
昨日的世界(五)
最喜欢这样的日子了,雾白充斥着整个天地,世界只剩下门前屋后的房子、田地、小鸡、小鸭和每个天真可爱的小女孩,还有屋旁的十几棵参天大树。周围的一切都隐没了,隐没在那白茫茫的雾里。家里只有奶奶和爷爷,所有的因素都是宁静的,雾里飘散着对面的柔和的歌声,如雾般柔和。独坐在屋檐下,止水般宁静地望着小鸡欢叫、小鸭梳理羽毛,有时跑过去和无忧的小孩一起吹泡泡,然后看着那泡泡飘向柔白的雾天里。好漂亮的泡泡,感觉真好,让宁静的心只剩下快乐,或许还有幻想。 霜冻过的竹叶有些发黄,掺和着雾白,朦胧地留在这幅完美简单的画里。那如影母子大杉,依然如故,一高一矮,一胖一瘦。再简单宁静,莫过于春影似雾的山村了。荒芜也隐于雾里,忧伤也隐于雾里,所有都隐在了雾里。你想听吗?听雾里的猪叫,听雾里的鸟鸣,听雾里的车响,听雾里的欢闹。雾里有一切一切的现实和幻想。没有不和谐的因素,只有雾白,雾白,雾白。 延伸到天尽的雾白中的电线,或许代表那漫漫长路,那路的开端永远是这端的静静站立等待的电线杆和这房子。每次都回到这电线杆,回到这雾里,回到这宁静,回到这和谐。 最是今年雾迷人。 ——2005.1.29 人是会长大的,会的。 时间依然是最公平的,对每个人都是一样的。总有一天,我们都不得不面对这世上我们会碰到的许多事。所以我们终于会学会自己去处理,去接受,而不再幼稚。 命运如此地安排,谁又能抗拒得了那样一种平稳的框架呢?平淡地看待和成熟地面对似乎一开始就成为我们要去实现的。 继续吧,没必要刻意去规划,却要做好准备,毕竟生活还是无常的。 ——2005.9.3 当一切都结束时,不属于我的一切人、物都从我的世界里消失的时候,我还会剩下什么呢?什么是值得我去付出的呢?有人说当我们都成为一坯黄土的时候,我们只剩下别人对我们的记忆,只活在那些依然想着我们的人心中。 所以呢,还要多说些什么呢?平静地去好好把握每一天,不要虚度年华,而今,依然不晚。自尊,自信,自理,慢慢地走出一条路。 ——2005.9.11 记不得今天是几号了,一段时间沉在书里之后,今天突然又觉容而怕,似乎有什么东西没做好。不知道哪里来的压力?好像没有什么是能真正留下来的。喧嚣之后那种人去楼空的感觉突然在心里扎根?不要。 电话卡里剩下3、4元,一直没再去充值,只是没有零现金了。想打电话没得打,即便卡里有钱又能打给谁呢?那些逝去飘去的东西加上这样冷风拌成的凉意荡在心里,使感情真心的人难过,别人怎会理解呢? 一丝感伤随着知秋的一叶徐徐飘落,想就叫人心痛。 ——2005.11 翻开旧旧的《视野》杂志,是今年年初买的,有几段话真的不错,摘其精华如下: 只有完全成熟的人,才有真正的秘密;不太成熟的人,只有暂时的秘密;不成熟的人,没有秘密。 如果你是个铁骨铮铮的好男儿,就应该学会把痛苦作为一种秘密深埋在自己宽厚的胸膛里,永远用你的微笑去面对父母,去感染妻子,永远的用你的笑声去浇灌孩子烂漫的心灵。 意志薄弱的人,为了摆脱孤独,便去寻找安慰和刺激;意志坚强的人,为了摆脱孤独,便去追寻充实和超脱。 感情上的幸与不幸,只有当事者心里最清楚,旁人常常在妄加猜测。有的人脸上有太多太多的微笑,是因为心中有太多太多泪水。 ——2005.11 以后应该少吃些泡面。 泡面的味道总是那么迷人,泡面对于我而言还有许多特别的意义。泡面伴我至今,有许多事情和泡面扯上关系,所以吃泡面总会令我想起许多许多的情景,有许多美好的回忆拌在泡面的香喷喷热气里,有许多伤感的回忆混杂着泡面辛辣的味里。 时间在前进,泡面在变化,心情却总会流连、重复、循环。 吃泡面的时候是幸福的。 ——2005.11 很想事情都朝着好的方向发展。理性的白天里,应该知道如何去做。背负着的令人不安的因素深埋在地下。 飘流着是没有理由、没有借口的,此而让自己放游的。每个海风于吹的日子都该有所得,为了心中遥想的路而奋斗。 毕竟要为自己负责,稳健的心态才能成为真正成熟的人。付出才有回报,真诚做人的原则永不悔。 ——2005.11 我思故我在。想象的天空里梦想在延伸,荷默有自己理性的原则,用心真诚地为人,坦然面对挫折和胜利,健康成长,梦想会实现。 做有建设性的努力,不再孩子般思考问题,成熟是稳健的。美好的回忆留下,伤感的故事沉淀。亡羊补牢,犹未晚。 每天都是新开始,好好地把握才能成功。 ——2005.12.17 得失之间,存乎一心。 平凡的或伟大的都是一样的。学会做一个普通人有时候很有必要的。所谓善者,才会是大家。开阔的,包容的,才会是精华的。视野大,才不会留于一时的捉襟见肘。所谓大家亦有相同之处。或者称之为修养,文明的成分。 美好才能赏心悦目,至于糟粕自当远之。勤快是可以弥补环境的先天的缺失。不怀偏见与明亮的胸怀是应该自然流畅地融入本身。 至于拍案而起之锋则可取其气而隐其形,不必拳脚相加、口诛笔伐,礼仪相待,当之谓修为、教养。 ——2005.12 没有任何进展,效率很低的时候是最让我伤心的时候,希望还只是遥不可及的梦想,或幻想。I want to catch something,但是事实让人很失望,心里真是莫名地难受,好难受,好难受。除了努力,就是泪了,真希望事情早点做好。 ——2006.3 感冒了,昨天头非常的痛,浑身无力,多亏了同学的感冒药。折腾一天之后,头不痛了,然今天开始流鼻涕了,好难受。但相对于昨天那种程度来说已是不可多得的好,至少有力气,可以吃点东西,不至于爬都爬不起来。仍旧是不停喝水,汗水也就不停地浸透全身衣物。想哭,真想回家。什么都做不了,也什么都不想做,只想早点结束这非人的日子。 ——2006.7 台风真频繁。六月、七月、八月、九月的时候,台风会有好几次。 台风来的时候总会带来风雨,心里就总会凉凉的,不知道以后台风的时候自己会是在哪里度过的。 梦里的泪光,枝枝节节,牵牵连连。漂走了,永远不会回来的似乎只有自己懂。 空间要撑起来,生活总是挤压空间。 萍真的很忙,我要去打扰她么?一个老是不成熟的人,可恨。 有时偶尔觉得自己漂的好远了。悲伤深处的圣光还是没见到。 伤神的台风,凌乱的夜晚。 ——2006.7 当许多人都不再写日记的时候,我却还把自己置于这字里行间。 迂腐的只是形式而已。 跃跳度太快意味着不合逻辑,而不合逻辑的就是可笑的。 不懂你在说什么! 当然我明白你想说什么,你想表达什么,然而你没表达清楚。 天真,幼稚。 真的是这样吗? 你相信吗? 梦里的月光迷人,人憔悴。 ——2006.7 治一种病症的药是好药, 治多种病症的是止痛药, 包治百病的是假药, 药到病除的是毒药。 ——读者小语 ——2006.9 对于爱情,是不能说的,写的。 爱情就多用心,感觉,把握。 婚姻就微调。 ——2006.10 当然,又是过了很久,才坐下来思考。平常的时候,有时会突然不知道身在何处,将来要做些什么。常常情况是这样的,郁闷大了,失落极了,全身上下充满不安全感。迷惘是非常容易的,但是因为这样,所以努力的时候有个方向、目标。又常常是这样的,挺高兴的。这次一不小心咸鱼翻身了,然而一小段兴奋期过后,你才发觉其实自己依旧是那个自己,前进的路上更需要静下心来去做些什么,踏实地努力着,点点滴滴地把握和渲染,也许这样心灵才会平静,生活才有意义,生命才具价值。 ——2006.10.11 曾经有一段话陪伴了我。 想永久地记住: 面对失落的痛楚,不要把悔恨的旧梦重拾。沉浸往事只能倾斜心灵的天秤,寻觅过去只能拾回尘土的梦幻。面对失落,应勇敢地追求新的目标,找回精神的追求。失去太阳,请不要流泪,我们还有群星。 ——2006.10.11 希望能成熟点,让自己的优点发挥的作用大些,不要被缺点绊住脚,要懂得扬长避短。 如果一个环境下没法改变自己的形象,那就换一个好了。某些不可能擅长的东西不如放弃,尽量不要被生活激怒,让平和的心态,坚韧的心占重点。回忆是个漫长的过程,相信自己可以的。头脑要会冷静,尽量不要得意忘形或自以为是,不可以轻视任何人,平等地对待自己与他人。 坚持这样,才会充实,才不会给自己抱怨和后悔的机会。一个人可以哭泣,绝不可以失去自我和没有勇气。 就这样。 ——2006.10 当我试着给未来一段日子列出一串长长的清单时,当然是指专业书目,我突然想,人的精力有限,而这个世界上的书何其多也,难道我真的会将如此众多繁杂的知识都弄个清楚?况且并未深究,而只是想管窥一斑,都已有如此之多的了。 于是我想是否该重新考虑一下舍取,因为大部分时候要想做出精品只有一种办法,那就是:只做一件事。许多人坚持不涉及另外领域而只是专心一事,但他们做的却绝对是这世上做这事做得最好的。也许,我也因此该专心一事了。 想要的太多、太离谱,反而什么也要不到。明白了这一点,也就懂得如何活得快乐,活得踏实了。 ——2006.10.29 注定着我不是个甘于平淡的人,看过别人的奋斗历程尤其如此。然而每每只能在想象里看到那些行动,注定我极少地实现那些想来令人激动的事业。原来我是如此的保守与不敢冒险。 心里的躁动与不安总是要涌出来的,有时候显得只有去等待与忍耐,也就是说总有一天要去实现那样的抱负吧。 然而我的性格与环境常显得不谐调。也许我还缺少一些实现梦想的要素,譬如说一个伙伴。实力呢? 难道注定我是个学者? 学海无涯,生存的压力又是常有的。也许眼光该放长点。可能环境影响,有时显得不如别人那样大方,或许我无法不去想这些,因为我不是别人的缘故吧。 ——2006.10.30 一个人默然前行的时候,有时会感到渺茫与失望之极,不知道从何拾起。猛然间会发现自己能会的原来如此稀少,那种失落的感觉会使我沮丧。 为何自我组织也许是要解决的更为本质的东西吧。 分形,如此美妙的数学我喜欢。
2014年2月8日星期六
昨日的世界(四)
每次整理旧文档,都能在角落里找到以前写的碎片文字,故曰「昨日的世界」。下面这些是写博士毕业论文的那段时间的碎片。无论想法我现在是否还赞同,都在此记录,保持原本的内容,以时间为序。 ---------- 20120312 ---------- 1、开源的本质是我想用我开发,我开发自己用,觉得别人也可能要用,于是我开源。我开源,如果有人觉得他也想用,于是他可以参与开发。并不是我要参与开源,所以开发。 2、封闭的坏处是把人绑定在一个平台上,限制选择,20年前是微软,如今是苹果,如果以前微软是邪恶的,如今之苹果亦然。 3、使用CMD的理由是,windows原生的,不是用第三方exe的原因是保证任何pc上都可以用,js和vb脚本可以用的原因类似。 4、苹果的AppStore依然是卖盒装软件的思想,其做IPAD,提出postpc的目的很可能是为了把pc干掉,因为pc上的盒装软件已经死亡,所以他要创造一个新的封闭环境来维持盒装软件的思维。其对手是Google和亚马逊。 5、所有的AppStore最终都会饱和,每个领域的软件都只剩下一些强势软件,于是开发者在上面的利益渐渐变薄,开发者生态链无法维持而走下坡路,走HTML5之web路线才是正确的路线。做客户端也类似,要摆脱盒装软件思维,这也是互联网企业的精髓。苹果不是一家互联网企业。 6、豌豆荚这种可以随意下载各种盗版软件的软件是会毁掉Android的,原因是因为盗版软件并不是专有软件的死敌,而是开源软件的死敌,盗版软件使得普通用户不会想到去用开源软件。这对开放的Android来说是不利的,正如过去30年来pc上的盗版软件一直都是开源软件的死敌一样。由此可见李开复的创新工厂是一个没有多少原则和理念坚持的拷贝工厂,与YCombinate有天然之别的差距,Y Combinate的创新理念很多都很让人震撼。 7、版本管理是需要的,即使只是自己写自己用,如果有个版本管理,比如使用Google Code svn仓库,哪天有人需要用最近版本的时候就可以去直接checkout出来。 8、GOF设计模式是针对OOP编程打的各种补丁,在非OOP语言里面未必适用,比如javascript里面生搬硬套GOF的设计模式就很奇怪了,javascript更多的语义是函式的,而不是物件导向的。 9、专注是很重要的,专注于那些你认为更有价值能让你举一反三的东西上,而不要被那些繁华喧闹的表面的东西所累赘。只有坚持一点一滴去积累,才能厚积薄发。而每一次的前进并不就代表使命的完成,而只是进阶路上的一小小步伐。业精于勤荒于嬉。 10、专注的技术是否真的能改变世界,我觉得我们还是要首先让自己懂得沉淀。有一颗坚韧的心,不被外界的各种走捷径的坏习惯所诱惑,坚持原则的一致性,努力的实践性。这样无论如何,你是能做点扎实的东西出来的,未必会如现今这个言必称成功的世界所定义的那样成功,但在于修为上的自我完成。 ---------- 20120315 ---------- 1、任何一件事,都应该用技术的方式去对待。何谓技术?技术意味着专业,不是像门外汉那样手忙脚乱,行事没有章法。所谓章法,就是纲举目张,凡事都得有个清晰的目录式设计在脑海中。好记性不如烂笔头,作为专业技术人,应当时刻用手中的工具将抽象和模糊的东西具象化,并且有高效的执行效率。什么叫高效的执行效率?想到一个东西,一个点子,一个解法,都立刻记录下来,形成文档,是一种高效。做事情懂随时懂得遇3则优的原则,批处理的思维运用自如。专业是与差不多先生格格不入的,比如对于汉字,决不允许错别字的存在便是一种每个人都可做到的专业。对于一个事件,是人云亦云,还是独立思考,这便是区别。专业和技术,意味着举一反三,知识和能力的迁移。 2、气质,是一种心态和形态。30而立,很多以前吊儿拦挡的习惯都得改掉。 3、几句从小到大的名言重新拾起来。所谓「朝花夕拾」? 凡事预则立,不预则废 业精于勤荒于嬉 行成于思毁于随 千里之堤,毁于足下 静坐常思己过,闲谈莫论人非 人生在世学几何,学了几何又几何,不学几何又几何。 4、白天忽然想怂恿spacenet去读研,觉得如spacenet这般不做则已,一但认真去做一件事,必然在技术上吃的很透彻,做出来的东西绝不是忽悠人的,很精品很精髓的风格,如果去读研,比然能留下一段传奇。在等公交车时半开玩笑的跟spacenet说起,他立即用自己一贯的迅速回应说,他就本科生水平,在美国他就是本科生水平,研究生的东西(比如数字图像处理,上次他说过),他是看不懂的,他现在就是本科生水平。姑且不论spacenet是否属于自我设限,就我所知,他在很多方面,包括实践能力、方法论等等都是属于上乘的,至少在厦门,他是当之无愧的windows cmd脚本之王。解决问题的方式方法,完全符合计算机科学的内涵。而且他看过诸多各类技术和哲学类书籍,在逻辑方面的反应其实远超过我的速度。我只是在抽象层理解上比他多训练了好多年,我这边博士生很多时候啃东西未必有他那么透彻和精髓。spacenet说自己只有本科生水平,多半是指在计算机科学的数学部分上他看的吃力。而据我看过的书《黑客与画家》分析,计算机科学本质上是一个多学科的杂物,比如涉及到硬件部分实际上可看做是物理学的部分,而涉及到软件部分,则属于编程部分,而涉及到目前的很多研究上,特别是发paper的那部分,实际上很多人做的是数学,而非计算机,计算机只是他们的一种实验。这可以举图像处理,我跟过一小段时间,用到的很多论文都实际上都属于应用数学,只是带有很大比重的实现算法的编程部分,许多计算机系的硕士或者博士,压根就没把那些数学部分理解掉,甚至推导都没过一遍,这是糊涂账部分。当然,并不是说你数学很牛逼就可以把这块做的很好,就像一个英文很好的人未必能写出莎士比亚的作品一样,数学只是一个基本的行内人都看得懂你在说什么的通用科学语言和工具;同样道理,不是你编程很牛逼就能做好研究,编程很牛逼只是说明你对某种语言掌握的很到位,你对软件设计很到位,但计算机的科研,不只是做软件这么简单的事。我理解起来,计算机科研真正做的好,是必须综合以上几部分的理解力之后,加上创造力和持续探索的精神才可能做出点什么出来。一如我在数学领域所理解的一样,能把数学的知识层面吃透的人实际上很多,但是真正有创新力的不多,创新是需要有想象力和构造能力的。我最欣赏的莫过于欧拉、高斯、黎曼、拉格朗日等等构造大师。再提起,创新之前得会找问题,好的问题是我们所缺失的,100多年前希尔伯特提出23个数学问题,使得数学在上个世纪上半叶取得了辉煌的成就。我们国人学生,甚至老师,往往提不出什么问题来做,一般都是所谓跟踪热点,在哪个方面上都落后于人,这当然有多种原因,比如没有专业方向所对应的发达产业,实际上你提的问题都是闭门造车。 5、电子书实际上并不会真得就完全取代纸书,因为电子书再怎么发展,也无法取代实体书的那种质感,随意翻页翻阅的感觉。Apple的新版电子书阅读器诚然在书籍的领域取得了挺大的进步,然而据spacenet观察,那种加入多媒体的手法,在精确性敏感的理工科书籍上有明显的优点,但是在人文哲学领域未必有优点。打一个比喻,很多电影再怎么好看,也总是无法取代原著。我越发喜欢看小说甚过看电影,电影的画面定格给于观众的想象力空间有限,书则不同,带有大量的想象空间。这其实涉及到1对1映射,还是1对多映射,甚至多对多映射信息的关系。一千个读者就有一千个哈姆雷特,多媒体恐怕在这方面未必胜于文本。再罗嗦一句,象形文字最早就是图画。 6、我讨厌病毒和木马,不过我更讨厌杀毒软件制造虚假的病毒和木马威胁感。自由和安全,都应该交予自己。 7、封闭的格式应该去兼容开放的格式,而不是开放的格式必须去兼容封闭的格式。 8、IT产业,什么才是其核心的价值?信息,意味着什么? ---------- 20120316 ---------- 1、遇到一个问题,从现在开始,要避免不分析问题的前因后果,不对问题的上下文做一番调查就开始做出回应,或者试图毛毛糙糙的把问题推给非义务人去解决。从现在开始,放弃一切试图让非义务方解决自己造成的问题的思维方式。独立之思考,当然需要以独立之解决问题为支撑,否则,独立之思考只是及其狭隘的。 2、谨慎让朋友帮忙,很多时候,你认为不是问题的事情,可能对朋友来说是很为难的事。没有对你有这种义务,这个经常会犯的错误,早该反思反思了。任何情况下,对有隐式和显式雇佣关系的对方,不要混淆雇佣关系下形成的习惯和友谊关系下形成的习惯。否则,会造成很多问题。 3、spacenet人很好,我没说要他帮我弄一个充电器,他却虽然吐槽了好几次,今天却给我弄了个5.3伏的充电器,我突然觉得很惭愧,跟spacenet接触这么久,明明很多正确做人做事的道路都听过无数次,还是在自己身上残留很多坏习惯,很多时候却试图用自己吐槽过无数次的那种思维方式去解决自己遇到的问题。这算是一种隐性的叶公好龙吧,静坐常思己过,我会一点一滴改掉的。 4、毕业这件事上,自己一直没能正式面对,论文投稿的事也怪自己。想想5年前本科毕业的时候对论文的差不多先生思维导致自己的本科毕业论文很一般,几乎是很水,现在难道要让自己重复当年之遗憾么,我想我不应该让历史重复,所以,我决定把最后的时间好好用上,认真把自己的论文写出色。人生难得几回搏,此时不搏何时搏。 5、重构c++代码的时候,觉得以前的很多代码特装B,明明不需要用到那么复杂的东西,却设计成那样的复杂,一个人想要提高对代码的敏感度,最好的方式是每隔一段时间都去重构自己之前的代码,长久习之,定能成大器。现在我也开始讨厌随意使用模板类,感觉模板类只应该由基础类库提供,自己的代码非不得以不要使用,尽量用简单的方法去解决问题,而不要使用各种所谓高级语言特性,对语言特性的热衷现在开始衰退了,不过并不意味着语言是无所谓的,只是说在使用任何一个语言的时候,都能够控制得住自己,保持简洁。不过度设计,过度实现。这很符合人生哲理。 ---------- 20120324 ---------- 1、凡事预则立,不预则废。 ---------- 20120522 ---------- →白驹过隙 打开log文件夹一看,上次写点随笔已是两个月之前的事了。时过境不迁,翻看当时的日志,犹如昨日之记录。毕业季的这几个月是煎熬的时光,也是磨炼心境的阶段。之前几年欠下的一屁股时间债都堆积在那,我只有一段一段去偿还。凌云六725楼、海运实验楼301和芙蓉餐厅之间三点一线,简单的重复累积着效率、沉淀着心情。未来不再迷茫,梦想不再模糊,依旧的追寻梦想和理想。人说三十而立,我不知道别人在靠近三十岁时是怎样的心情,我自己则是对「三十而立」有着一丝丝感觉了。读书二十年,在书堆中坚持过、在游戏中沉迷过、在亲情中哭泣过、在爱情中执着过、在数学中抽象过、在程序中编织过,不变的是追寻。
订阅:
博文 (Atom)