-
《SICP》第一章最后有个练习非常有意思:求n次方根。书的第一章几乎用了所有的篇幅来讲一些算法和抽象,并且在第一章第一节就说到了用牛顿迭代法来求一个数的平方根,在第一章最后一节的练习中要求一个数的n次方根。
根据书上前面几节的说法,求x的平方根就是求函数y->x/y的不动点,而不动点的求法就相当简单了,随便猜一个数带入函数,如果结果不好再将结果带入函数,最终函数总会得到不动点。但是如果直接这样求平方根会有一个问题:函数并不收敛(假设最开始猜y,那么带入函数会得到x/y,将结果再带入函数又得到y),补救办法就是使用一个叫average damp的方法(实在找不到中文的翻译,直译过来...
-
人不是可以机械化处理的机器,他的生命尊严来源于他的非理性的情感。——许知远
以前我总是认为人区别于动物就是因为人的理性,正是因为理性人类的科技才会如此发达,人们才可以使用各种各样的人造物品,也正是因为理性人们的社会才有秩序,而不像动物群体一样需要靠暴力来进行统治。因此我也就想当然地觉得作为正常的人应该抵制自己的非理性,也就是抵制自己内心的“兽性”。因此我尽量让自己变成一个理性的人,理解所有的事情,根据这些了解再去决定,尽量避免无意义的谈话,只做自己认为有价值的事。这样的做法在很大程度上让我做事和学习变得非常有效率,但是随之而来的是不快乐。这是一件非常矛盾的事情——我可以让自己做...
-
Paul的书把lisp的宏夸到了无以附加的地步,但是作为一本闲聊的书它并没有深入介绍lisp的宏,甚至连基本概念都没提到。这对于学习lisp的人非常有害——它会造成一种莫名的崇拜,并且这种崇拜还是对于未知的崇拜,读者根本没有理解任何东西。这样的崇拜让我在读第一本lisp书时就找宏看,结果在没有理解其他部分时就接触到宏,当时就看得一头雾水。而且一些强大的东西往往也会有很麻烦的副作用,宏也一样,但是Paul并没有把这些问题讲明白,其实在一些其他正经介绍lisp的书中都是非常小心地强调宏的危害——良好定义的宏会有非常强大的力量,但是一些垃圾宏会让整个程序变得难以理解并且混乱不堪。
其实我看懂...
-
似乎很少有人刚开始编程就使用lisp,一般常见编程入门语言主要是C,Java,python等非常流行的语言。许多学lisp的人应该都和我一样是半路迁移过来的,到现在为止我学lisp断断续续的有半年了,现在总结一下这半年来都做了什么,顺便帮助一些其他的想学lisp的人。我学lisp时看过的书见这个豆列。
学习lisp的痛苦和好处
一般从其他语言迁移到lisp会经历各种痛苦,因为它有太多的其他语言不具有的概念:闭包,词法作用域,高阶函数,宏,即使撇开这些不谈一般人也会受不了lisp那么多的括号。其实括号这个问题也并不严重,最开始我刚从python迁到C就有很大的不适应:C竟然要求每个表达...
-
今天同学遇到了一个很多Linux使用者常见的问题:恢复grub。他的情况是这样的:硬盘上有两个操作系统,一个Windows 7,一个Ubuntu,由于Windows中毒(既然Windows容易坏为什么还要用。。),所以把Windows重装一遍,重装一遍后会发现在启动选项中没有Ubuntu了,这很正常,因为Windows的引导程序不能识别Ubuntu系统(这就是为什么Ubuntu要在Windows装后再装的原因),而重装系统会清掉原来的引导程序。为了能重新启动硬盘上的Ubuntu需要将Ubuntu的引导程序也就是grub装上。
首先从Ubuntu安装盘启动,选择试用模式,启动好之后打开终...
-
在学习编程时最重要的是了解程序解析器或编辑器的运行过程,有很多解析器模型可以用于模拟这些过程,在学习支持lambda函数的语言时有一个非常好用的解析器模型——环境解析模型,这个模型在《SICP》中提到,这方法对于学习lambda解析很有效。几乎所有支持lambda函数的都可以使用这种方法来模拟解析器运行,目前我知道的支持lambda函数的语言有JavaScript, Lisp和Haskell。
环境
想要理解环境解析方法就必须先理解环境。环境就类似于存储键值对的通用仓库,所有对变量值的查找都是在环境中查找,而环境则是由更小的帧对象组成,如何理解呢?下图显示了几个由帧组成的环境
...
-
什么是Memoization
似乎我已经在很多书上看到函数的Memoization了,《JavaScript语言精粹》提到过,《SICP》也提到过。然而《JavaScript语言精粹》里面提到的那个memoization没什么意思,因为它那个函数并不通用,但是《SICP》提到的就不一样了,它几乎做到了通用性。
从维基上可以看到具体的定义,简单来说Memoization可以对重复并且计算量大的函数进行优化,并且该函数必须没有状态,也就是说无论调用该函数多少次函数值都一样。Memoization的做法就是将计算的值保存起来,并且在下次再调用同样参数时直接返回该值。
Scheme的Mem...
-
好吧,这是我第一次写软文,但是今天刚刚试用了ubuntu11.10,感觉非常好。这次ubuntu使用了全新的LightDM登录管理器,非常漂亮,而且如果将面板调为半透明非常有感!
现在我算是明白Canonical公司发布ubuntu的规律了,众所周知Canonical每隔6个月发布一个ubuntu版本,但是并不是每一个都值得去升级的,每隔两年它都会发布一个LTS(长期支持)版本,这样的版本是绝对推荐升级的,从ubuntu发布的历史来看8.04和10.04都是划时代的,但是其他的非长期支持版本就并不是太引人注目了,主要由于每次非长期支持版本会引进很多新功能,界面的跨度比较大,像11.04...
-
最开始在学习git用法的时候就听说了git不像其他版本管理软件(subversion)把版本信息分别放在各个子目录,而是将整个版本信息放在项目的根目录,当时就觉得这种实现似乎很有意思,但是却不知道如何实现这一点,因为每次运行git add等命令时都有可能在任意子目录。唯一能想到的方法就是绝对路径:所有版本的文件的路径都使用绝对路径来表示,但是这样一来将项目的目录进行移动或者分布式开发就有问题,而且使用od(1)来查看git的index文件也发现存的是相对路径而不是绝对路径。
git的实现
在源代码中就可以找到实现原理:几乎所有的git命令都会在启动时调用setup_git_direc...
-
“程序需要对非常难以计算的数值进行缓存,使用空间换取时间”
相信大多数写过程序的都知道这一点,但是如果没有真正对比一下是不会留下深刻印象的。
今天看《SICP》里提到斐波那契函数是树形的递归调用,突然想到计算斐波那契数可以非常好地显示缓存的威力,斐波那契数求法如下
unsigned long long fib(unsigned int n){
if ( n < 2 )
return n;
return fib(n-1) + fib(n-2);
}
这是一个递归的函数,对于参数为4的调用树见下图:
斐波那契函...