计算机程序的构造和解释(Structure and Interpretation of Computer Programs)

本科毕设的时候林老师推荐过这本书,但是当时看目录就不知所云。这本书是18年9月刚读研究生的时候买的,只是一直没看,连塑封都没拆开。今年因为疫情的原因没上学,大概从3月份开始,花了3个多月的时间仔细读了一遍,不得不说这书是一片新天地,尤其是当你写了很多年的命令式。

第一章是构造过程抽象,印象最深的就是用一种通用的过程来实现对一组聚合元素的操作,应该是模板和泛型的概念。另外如果觉得这括号太蛋疼,一定是因为没有看视频教程。

第二章是构造数据抽象,感觉和面向对象是一个概念,通过实现有理数类和复数类,将Lisp中的所有数运算进行了统一。之前看书没有注意到的一点是,Lisp中的cons可以绑定到函数上,视频链接见这里的64:17。

(define cons(a b)
	(lamba (pick)
		(cond ((= pick 1) a)
			   (= pick 2) b))))
(define (car x) (x 1))
(define (cdr x) (x 2))

用C++11中的lambda表达式和function模板来模拟,应该就是下面的代码,但这里有两个问题:

  • 由于函数的返回值只能有一个类型,所以ab必须同类型,不能是两个类型,可能这就是C++不支持的闭包吧?
  • Cons构造的过程,到底是否和lambda的代换模型一样?也就是语句是否真的被替换为了return 37return 49
#include <iostream>
#include <functional>

using namespace std;

template<typename T> function<T(int)> Cons(const T & a, const T &b)
{
	return [a, b](int pick)->T
	{
		if (pick == 1) return a;
		else if (pick == 2) return b;
		else return T();
	};
}

template<typename T> T car(const function<T(int)> &c)
{
	return c(1);
}

template<typename T> T cdr(const function<T(int)> &c)
{
	return c(2);
}

int main()
{
	auto c = Cons<int>(37, 49);
	cout << "Contents of Address part of Register:" << car(c) << endl;
	cout << "Contents of the Decrement  part of Register:" << cdr(c) << endl;
	return 0;
}

这也就是说函数式编程中,数据和过程的界限非常模糊。

第三章是还是数据抽象,但是此时的数据带有内部状态,因此要用环境模型代替代换模型。硬件电路模拟约束传播系统这两个例子很有意思。最后一部分的流是为了解决前面出现的串行化问题而提出的一种新的计算模式,我只看懂了有限流部分,无穷流和延迟操作部分没太理解。

  • 对于硬件电路,每一个元器件的输入连线中保存了一些过程,这些过程就是设定输出信号的值,当输入信号改变时,会将这些过程加入到时间序列中,等待基本门电路的延时之后调用这些过程,所以一个输入信号就可以层层传递到输出。如果写过Verilog和VHDL就深有体会了,特别是那个propagate,倍感亲切!
  • 对于约束传播系统,主要用来根据恒等式中一些已知变量的值,来计算另一些变量的值,加减乘除等运算被实现为约束,变量被实现为连接线,当连接线被赋新值时,要通知其连接到的另一个约束,而这个约束会对除通知者之外的所有连接线都重新计算赋值

第四章是元语言抽象,实际就是使用Lisp分别实现了Lisp解释器惰性求值解释器非确定求值解释器逻辑式语言解释器

  • 惰性求值解释器就是正则序求值解释器,书中用的Lisp是应用序,也就是在求值一个过程时,所有参数都需要求值才可以,而惰性求值就只有在参数实际使用时才进行求值
  • 非确定性求值解释器的名字有点唬人,反正觉得类似于深度搜索,在有多个解时,每执行一次就可以得到一个解
  • 逻辑式语言解释器的直观理解就是SQL语言,代码量比较大,每个过程都好理解,集成后的完整程序没仔细分析

第五章就没什么新鲜的了,首先定义了新的机器语言,最后将Lisp程序和Lisp解释器编译为该机器语言运行,还不如去看编译相关内容。不过这里面还是有几个值得研究的内容,一个是垃圾收集,另一个就是编译和解释互相调用的混合策略,同时利用了编译的效率优势和解释的排错优势,有点类似于前几天在知乎上看的一个回答,用python训练,模型没问题了再用C++重写一遍。

现在的大学教育一半只能接触到命令式编程,因为这和个人计算机最接近,但其实像C++、Java和JavaScript中都引入了函数式编程的概念,这些特性让编程变得更高效了。

1,过程作为返回值 在1.3中我们明白了高阶函数之后,“用一个过程作为另外一个过程的返回值”则是稀松平常的事情了,比如下面的代码: (define (f x) (+ x 1)) (define (g) f) ((g) 2) 函数g没有参数,其返回值为函数f,所以((g) 2)就运算结果就是(f 2),最后运算结果为3。 上面是用一个已命名的函数作为返回结果的,相应的,也可以将一个“匿名过程”作为结果返回,这里的“匿名过程”也就是我们的Lambda表达式,所以上面的代码可以改造成: (define (g) (lambda (x) (+ x 1))) ((g) 2) 那么((g) 2)的运算结果就是((lambda (x) (+ x 1)) 2),最后运算结果为3。 2,牛顿法 学到这里,你可能需要复习一下高等数学的基本内容,包括“导数”“微分”,高数的在线教材可以在这里找到:http://sxyd.sdut.edu.cn/gaoshu1/index.htm 关于牛顿法的介绍可以看这里:http://en.wikipedia.org/wiki/Newton%27s_method ,下面是程序: (define (close-enough? v1 v2) (< (abs (- v1 v2)) 0.000000001)) ;定义不动点函数 (define (fixed-point f first-guess) (define (try guess step-count) (let ((next (f guess))) (if (close-enough? guess next) next (try next (+ step-count 1))))) (try first-guess 0)) ;定义导数函数 (define (D f) (lambda (x dx) (/ (- (f (+ x dx)) (f x)) dx))) ;牛顿法 (define (newton g first-guess) (fixed-point (lambda (x) (- x (/ (g x) ((D g) x 0.000000001)))) first-guess)) ;平方 (define (square x) (* x x)) ;定义开方,来测试下牛顿法 (define (sq x) (newton (lambda (y) (- (square y) x)) 1.0)) (sq 5) 3,“一等公民” 这里列出了程序语言中作为“一等公民”的语言元素所具备的几个“特权”: 可以用变量命名 可以作为过程参数 可以作为过程返回结果 可以被包含在数据结构中 4,练习1.40 求三次方程 x^3 + ax^2 + bx + c 的零点。 首先,证明 函数f(x) = x^3 + ax^2 + bx + c 是“可微”的: 由可导可微的性质知道,可导可微互为充要条件,所以,要证可微我们可以先证可导, f ’ (x) = (x^3)’ + (ax^2)’ + (bx)’ + (c)’ = 3x^2 + 2ax + b 所以f(x)的导数存在,那么f(x)可导,其必定可微。 其次,利用“牛顿法”:如果f(x)是可微函数,那么f(x)=0的一个解就是函数(x – f(x)/df(x)的一个不动点,其中df(x)是f(x)的导数。所以我们可以轻松得到下面的代码: (define (close-enough? v1 v2) (< (abs (- v1 v2)) 0.000000001)) ;定义不动点函数 (define (fixed-point f first-guess) (define (try guess step-count) (let ((next (f guess))) (if (close-enough? guess next) next (try next (+ step-count 1))))) (try first-guess 0)) ;定义导数函数 (define (D f) (lambda (x dx) (/ (- (f (+ x dx)) (f x)) dx))) ;牛顿法 (define (newton g first-guess) (fixed-point (lambda (x) (- x (/ (g x) ((D g) x 0.000000001)))) first-guess)) ;定义cubic函数,也就是我们题目中所谓的f(x) (define (cubic a b c) (lambda (x) (+ (* x x x) (* a x x) (* b x) c))) ;随便定义几个系数 (define a 3) (define b 5) (define c 8) (define result (newton (cubic a b c) 1.0)) ;定义一个验证过程,让其验证得到的解,是否让方程成立 (define (validate x) (= 0 (+ (* x x x) (* a x x) (* b x) c))) ;输出结果 result ;验证结果 (validate result) 比如上面我们计算 x^3 + 3x^2 + 5x + 8 = 0, 其一个解为:-2.3282688556686084 .....
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值