SICP 第一章 构造过程抽象 1

Chapter 1 Building Abstractions with Procedures

.title { text-align: center }
.todo { font-family: monospace; color: red }
.done { color: green }
.tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal }
.timestamp { color: #bebebe }
.timestamp-kwd { color: #5f9ea0 }
.right { margin-left: auto; margin-right: 0px; text-align: right }
.left { margin-left: 0px; margin-right: auto; text-align: left }
.center { margin-left: auto; margin-right: auto; text-align: center }
.underline { text-decoration: underline; color: green }
.bold { color: gold }
.italic { color: red }
#postamble p,#preamble p { font-size: 90%; margin: .2em }
p.verse { margin-left: 3% }
pre { border: 1px solid #ccc; padding: 8pt; font-family: monospace; overflow: auto; margin: 1.2em }
pre.src { position: relative; overflow: visible; padding-top: 1.2em }
pre.src::before { display: none; position: absolute; background-color: white; top: -10px; right: 10px; padding: 3px; border: 1px solid black }
pre.src:hover::before { display: inline }
pre.src-sh::before { content: "sh" }
pre.src-bash::before { content: "sh" }
pre.src-emacs-lisp::before { content: "Emacs Lisp" }
pre.src-R::before { content: "R" }
pre.src-perl::before { content: "Perl" }
pre.src-java::before { content: "Java" }
pre.src-sql::before { content: "SQL" }
table { border-collapse: collapse }
caption.t-above { caption-side: top }
caption.t-bottom { caption-side: bottom }
td,th { vertical-align: top }
th.right { text-align: center }
th.left { text-align: center }
th.center { text-align: center }
td.right { text-align: right }
td.left { text-align: left }
td.center { text-align: center }
dt { font-weight: bold }
.footpara:nth-child(0n+2) { display: inline }
.footpara { display: block }
.footdef { margin-bottom: 1em }
.figure { padding: 1em }
.figure p { text-align: center }
.inlinetask { padding: 10px; border: 2px solid gray; margin: 10px; background: #ffffcc }
#org-div-home-and-up { text-align: right; font-size: 70%; white-space: nowrap }
textarea { }
.linenr { font-size: smaller }
.code-highlighted { background-color: #ffff00 }
.org-info-js_info-navigation { border-style: none }
#org-info-js_console-label { font-size: 10px; font-weight: bold; white-space: nowrap }
.org-info-js_search-highlight { background-color: #ffff00; color: #000000; font-weight: bold }

Chapter 1 Building Abstractions with Procedures

Table of Contents

  • 1. 构造过程抽象

    • 1.1. 程序设计的基本元素

      • 1.1.1. 表达式(expressions)
      • 1.1.2. 命名和环境
      • 1.1.3. 组合式的求值
      • 1.1.4. 复合过程(compound procedures)
      • 1.1.5. 过程应用的代换模型
      • 1.1.6. 条件表达式和谓词
      • 1.1.7. 练习
      • 1.1.8. 实例:采用牛顿法求平方根
      • 1.1.9. 过程作为黑箱抽象
      • 1.1.10. 练习

1 构造过程抽象

  1. 心智活动就是:

    1. 组合. 将 simple ideas 变成 compound ideas
    2. 关系. 将idea放在一起, setting them by one another, 同时观察.
    3. 抽象. 隔离开实际中的相伴的其他idea, 从而抽取出 general idea.
  2. 我们研究 the idea of a computational process.
    1. 计算过程(computational process) 计算机中的 抽闲存在, 操作 data.
    2. 一套规则即 program 指导process的evolution. 就像法师用咒语控制精灵. 用咒语(program)来施展法术(process). procedure是咒语实体
  3. master有organize programs 的能力:预见,合理规划;防灾救灾;模块化.
  4. Lisp 是一种语言 describing processes. 类似 自然语言用来描述everyday thougths, 数学用来描述定量现象.
  5. Lisp本意只是一种数学记述形式, 用来处理一种特定形式的逻辑表达式(递归方程); 但也适合作为program.
  6. 名字来自表处理list processing. 通过新增原子和表, 获得符号计算的能力,如微积分;
  7. 最重要的一个特征是: process的Lisp描述(称为procedure)本身又可以做为Lisp的数据来表示和操作 许多威力强大的程序设计法术都是为了: 填平"被动的"数据 和 "主动的"过程 之间的传统划分 represent prcedures as data 的能力 使得 Lisp 非常适合于 写programs that must 操作其他 programs as data, 例如: interpreters, compilers.

1.1 程序设计的基本元素

  • 程序设计语言不仅指挥计算机,更是一种框架,让人在其中组织思想
  • 都有将简单认识组织成更复杂认识的方法,3种机制: 完全对应心智活动
    • 基本表达式,最简单的个体
    • 组合的方法,从简单东西出发构造出复合的元素
    • 抽象的方法,给复合对象命名,当作单元去操作
  • 程序设计中,处理两类要素:过程和数据 并不严格分离 ;简单说,数据是操作的"东西",而过程是操作数据的规则的描述. 对数据和过程都要提供上述3种机制

1.1.1 表达式(expressions)

  • 基本表达式:486和+都是.
  • 组合表达式(combinations):一对括号括起的一个表,表示 过程应用. 最左运算符,其余是运算对象 求值就是将运算符表示的过程 用于运算对象的值(实际参数)
  • 前缀表示, 优点:
    1. 使用可带任意个实参的过程,而没有歧义
    2. 易嵌套,允许组合式元素本身又是组合式

1.1.2 命名和环境

  • using names to refer to computational objects. We say that the name identifies a variable whose value is the object.
  • (define var 2) define是最简单的抽象方法,允许用简单名字去引用 组合运算的结果 emacs lisp: (set ‘<name> <value>) 或者 (setq <name> <value>)
  • 实际上, 构造程序,就是逐步创建出越来越复杂的计算性对象 ;逐步创建名字-对象关联, 解释器提供这种便利,并促进采用递增方式去开发调试. 这里所说的计算对象是维护在解释其中的环境?似乎可以拆分为, 构建和计算?
  • 环境 将值与符号关联,解释器必须维护名字-值对偶, 确定符号的意义;这种存储就称为环境;一个计算过程中可能有多个不同环境

1.1.3 组合式的求值

  • 组合式求值规则:

    1. 求值各子表达式;
    2. 将最左子式的值,应用于所有其他子式的值
  • 递归,树形积累
    1. 这一规则,是递归的,有调用规则本身的需要 子式又是组合式
    2. 可用一棵树来表示求值过程,结点为组合式,发出分支对应子式;求值就是从端点向上穿行组合,进行"树形积累" 每个节点都把孩子收到一起
    3. 反复用步骤一,直到不再遇到组合式而是基本表达式 不是函数调用,或者是使用内部运算符.即, 找到了机器码.,取出数和名字的值
      • 基本表达式:

        1. 数的值, 就是它所表示的 数值
        2. 内部运算符的值, 就是相应的 机器指令序列
        3. 其他名字的值 在环境中查找
  • 特殊形式
    1. 如define, 不是组合式 ,有自己的求值规则.
  • 这些不同的表达式(expression)(及相应求值规则)组成语法形式. the evaluation rule for expressions 可表述为 普通形式 + 特殊形式.

1.1.4 复合过程(compound procedures)

  • 过程定义的一般形式:(define (<name> <formal parameters>) <body>) 复合过程对应基本过程 emcas lisp: (defun name (formal parameters) <body>)
  • 过程定义,强大的抽象技术,为复合操作提供名字,以作为单元使用,隐藏实现, 然后使用就与基本过程完全一样。

1.1.5 过程应用的代换模型

  • 基本过程应用机制:解释器已做好 复合过程用用机制:形参用实参取代,对过程体求值.
  • 过程应用的代换模型: 取出函数体, 应用参数, 求解; 归于为其他问题, 不断求解.
    • 只是帮助理解意义, 不真操作过程正文,去代换; 实际是利用局部环境,产生"代换"的效果。
    • 第一个且简化的模型, 当问题变复杂时, 会引入其他模型.
  1. 应用序和正则序

    正则序求值(normal-order evaluation): fully expand and then reduce
    应用需求值(applicative-order evaluation): evaluate the arguments and then apply

    • 代换模型可用时, 两者结果一样.
    • 但, 正则序可能有重复求值 不同位置的形参都要计算一次; 代换模型不可用时, 正则序会很复杂.

1.1.6 条件表达式和谓词

  • cond,if

    • (cond (<p1> <e1>) (<p2> <e2>)…), 依次 看谓词pi,直到某谓词为真
    • else特殊符号,用在cond最后一句,永远返回,即else后谓词永为真
      emacs lisp: 没有else, 用t代替.
    • if是cond只有两情况的特例, 算predicate, 然后 选择一个分支;形式(if <predicate> <consequent> <alternative>)
  • 逻辑符合运算符
    • and,or,not

1.1.7 练习

					;1.1
10
(+ 5 3 4)
(- 9 1)
(/ 6 2)
(+ (* 2 4) (- 4 6))
(set ‘a 3)
a
(set ‘b (+ a 1)) ;如果不quote, 就会求值. set的两个参数都可以quote
(setq a 3 b (+ a 1)) ;第一个参数自动quote; 多对同时赋值, 两个一对.
(+ a b (* a b))
(= a b)
(if (and (> b a) (< b (* a b)))
    b
  a)
(cond ((= a 4) 6)
      ((= b 4) (+ 6 7 a))
      (t 25 ))
;emacs lisp的cond里面没有else, 用t. t的value是t.
(+ 2 (if (> b a) b a))
(* (cond ((> a b) a)
	 ((> a b) b)
	 (t -1))
   (+ a 1))

					;1.2
(/ (+ 5
      5
      (- 2
	 (- 3
	    (+ 6
	       (/ 4 5))))
      (* 3 (- 6 2) (- 2 7)))

					;1.3
(defun bigest (a b c)
    (cond ((and (> a b)(> a c)) a)
	  ((and (> b a)(> b c)) b)
	  (t c)
	  )
    )
;function 的定义形式和 scheme不一样.
(bigest 1 2 3)
(bigest 21 89 30)

					;1.5
(defun p ()
  (p))
(defun test (x y)
  (if (= x 0)
      0
    y))
(test 0 (p));应用序的话, 会不断求(p), 死循环; 正则序不会求(p), 直接0结束.

1.1.8 实例:采用牛顿法求平方根

  • 说明与行动,数学函数与计算过程 有趣的观点. 贯穿在现实生活中. 说的正确性, 做的现实性. 平方根函数定义:根号x = y,使得y>=0且y^2=x 正统的数学函数,能推导出一些一般性事实;但并没有描述计算过程,给一个x,如何找到y 数学函数与计算过程的差异是说明性知识 与 行动性知识 间的普遍性差异的一个具体体现 数学关心说明性的描述(是什么),而CS关心行动性的描述(怎么做)
  • 求平方根的牛顿法: 已有猜测y, 新猜测为 y 与 x/y 的平均值,该值会更接近实际的平方根
  • 不用特殊迭代结构来实现迭代

1.1.9 过程作为黑箱抽象

  • 过程抽象

    • sqrt有多个有明确分工的过程构成. 直接反应了从原问题到子问题的分解.
    • sqrt中square是一过程抽象;任何能计算出平方的过程都可用 一个过程定义需要能隐藏起一些细节,能被当作黑箱使用,不用弄清其中的具体实现。
  • 局部名
    • 约束变量: 形式参数的名字, 名字具体是什么不重要, 可统一更换, 约束于的一集表达式称为 该名字的 作用域
    • 自由变量: 非约束变量, 不能任意替换.
  • 内部定义和块结构
    • 对用户由暴露必要的过程,其他都定义到该过程内部; 这种嵌套定义,称为 块结构 ,解决名字包装(减少冲突)问题
    • 部分参数传递就不必要了,可以改为内部定义中的 约束变量, 这种方式称 词法作用域 , 省去很多参数传递. 约束变量在某范围内是有定义的. 自由超越了一定的范围? 约束,自由都是对于一定范围来说的吧?

1.1.10 练习

					;1.7
(defun sqrt-iter (guess x)
  (if (good-enough? guess x)
      guess
    (sqrt-iter (improve guess x)
	       x)))
(defun improve (guess x)
  (average guess (/ x guess)))
(defun average (x y)
  (/ (+ x y) 2))
(defun good-enough? (guess x)
  (< (abs (- (square guess) x)) 0.001))
(defun square (x)
  (* x x))
(defun sqrt (x)
  (sqrt-iter 1.0 x))
(defun good-enough? (guess x);用变动比例来衡量结束时间
  (< (/ (abs (- (square guess) x)) x) 0.001));guess是开方结果, 而x是被开方数.

(sqrt 9)
(sqrt 100000)
(square (sqrt 2984881264950492));统计一下计算次数呢?
(sqrt 0.09)
(square (sqrt 0.0009)) ;小值, 误差很大. 因为结束条件与0.001相关.

					;1.8
(defun cube-root (x)
  (sqrt-iter 1.0 x)) ;sqrt-iter不只用来求sqrt, 而是一种更通用的形式
(defun improve (guess x)
  (/ (+ (/ x (square guess)) (* 2 guess))3))
(defun cube (x)
  (* x x x))
(defun good-enough? (guess x)
  (< (abs (- (cube guess) x)) 0.00001)) ;cube, square写到了里面. good-enough?就不得不写两份.

(cube (cube-root 9))
(cube (cube-root 0.0003))
  • ex1_6: if,cond都是特殊形式,与一般求值规则不同. 都是"从上到下"计算. 定义的new-if使用组合式的一般求值规则, 没有短路性,所有子表达式都会计算,而死循环。
  • ex1_7:对很大和很小的y,good-enough?不用固定差值了,而用相对值,用变化和猜测值的比率. 太小直接停了. 太大结束不了, 左右震荡.

是什么和怎么做 是有区别的. 尾递归可以不需要迭代的特殊形式 而仅用函数调用 就实现迭代. 局部变量, 内部定义块结构, 作用域 都能有效的 增加代码的维护性.

原文地址:https://www.cnblogs.com/flameNoodleKing/p/9551679.html

时间: 2024-10-17 16:41:08

SICP 第一章 构造过程抽象 1的相关文章

SICP学习笔记及题解—构造过程抽象(三)

主要内容 高阶过程:以过程为参数和/或返回值的过程 lambda 表达式 let 表达式 用过程作为解决问题的通用方法 求函数的 0 点 求函数的不动点 返回过程值 过程是语言里的一等公民 (first-class object) 1.3.1高阶过程 过程是抽象,一个过程描述了一种对数据的复合操作,如求立方过程:(define (cube x) (* x x x)) 换个方式,也可以总直接写组合式:(* 3 3 3), (* x x x), 不定义过程,总基于系统操作描述,不能提高描述的层次,

SICP学习笔记及题解---构造过程抽象(一)

有段时间没看这本书了. 而且在做笔记的时候产生了一些疑问,觉得这样照着书做笔记没什么意义.于是乎,改变了一下做法.改成先提出疑问,记下重点,然后结合实际案例学习相关东西,最后附上题解, ok,下面就是第一次的笔记.(依旧是旧套路的) 本节内容 l  讨论基本的Scheme语法规则 l  过程的定义 l  代换模型 l  条件表达式和谓词 l  过程抽象 l  与C语言比较 程序设计的基本元素 所有的高级的语言都会在把简单的认知组合起来形成复杂认识的方法上有独到之处.而且每个强有力的语言都为此提供

计算机程序的构造和解释笔录(1):构造过程抽象

Q: SICP是讲软件工程么? A:部分,但并非全部.主要是模块化和黑盒抽象,计算机中两大主要基本思想.SICP关心的是:"当系统复杂度爆炸时(或者在此之前),我们如何通过有效的方法和手段去控制系统的复杂度?" Q: SICP是讲编译原理么? A: 部分,另外,如同书名说描述的那样,SICP中的"编译"都是"解释",这种解释的行为,无外乎就是用一种机器的计算行为去模拟另一种机器. 一个计算机语言并不仅仅是让计算机去执行操作的一种方式,而是一种表达

SICP学习笔记及题解---构造过程抽象(二)

主要内容: 表达式,值,define 过程的内部定义和块结构(上述示例已经解释) 分析过程(静态,描述)产生的计算进程(动态,行为) 计算进程的类型 线性递归 线性迭代 树形递归 计算的代价 第一部分: 表达式,值,define 1.总结表达式的一些概念 变量 如果一个变量没定义,对它求值是错误,求值中断,如果变量有定义,求值得到它当时的关联值 内部过程 对内部过程名求值得到某种特殊信息.如(不同系统可能不同) 组合过程: 对自己定义的过程名求值也得到特殊信息. 特殊形式的名字不能求值 例如,对

魔方方法篇第一章--------构造与析构

我们最为熟知的基本的魔法方法就是 __init__ ,我们可以用它来指明一个对象初始化的行为.然而,当我们调用 x = SomeClass() 的时候, __init__ 并不是第一个被调用的方法.事实上,第一个被调用的是 __new__ ,这个 方法才真正地创建了实例.当这个对象的生命周期结束的时候(指类被删除之后), __del__ 会被调用.让我们近一步理解这三个方法: __new__(cls,[...) __new__ 是对象实例化时第一个调用的方法,它只取下 cls 参数,并把其他参数

rocketmq namesrv 第一章启动过程

大家好,很高兴在这里跟大家分享下rocketmq源码实现,如有不对的地方欢迎指正. Namesrv顾名思义就是名称服务,是没有状态可横向扩展的服务.废话不多说了,直接贴代码.. 1,入口函数NamesrvStartup.main0 1.1 System.setProperty(RemotingCommand.RemotingVersionKey, Integer.toString(MQVersion.CurrentVersion)); 设置版本号属性 1.2 if (null == System

SICP: 第一章 之 牛顿法

#lang racket (define (newton-transform g) (define dx 0.00001) (define (deriv g) (lambda (x) (/ (- (g (+ x dx)) (g x)) dx) );lambda );deriv (lambda (x) (- x (/ (g x) ((deriv g)x))));lambda );newton-transform (define (fixed-point f guess) (define toler

第一章 MYSQL的架构和历史

在读第一章的过程中,整理出来了一些重要的概念. 锁粒度  表锁(服务器实现,忽略存储引擎). 行锁(存储引擎实现,服务器没有实现). 事务的ACID概念 原子性(要么全部成功,要么全部回滚). 一致性(从一个一致性状态转换到另外一个一致性状态). 隔离性(一个事务所做的修改在提交前,对其他事务是不可见的). 持久性(一旦事务提交,所有修改都会永久保存到数据库中). 四种隔离级别 READ UNCOMMITTED(未提交读): 事务即使没有提交,所做的修改对其他事务是可见的.  也称脏读. REA

第一章 袋子

第一章 袋子 简介 抽象数据类型(ADT),独立于任何编程语言,是对概念上定义的一组数值以及在这些数值上的操作的规格说明.而数据结构ADT在编程语言中的实现. 集合是一个将其他对象形成组并向客户提供服务的对象.典型的集合能使客户增删查检改它所代表的对象.集合的行为被抽象化的说明.集合是ADT,而ADT去不一定是集合. ADT袋子是集合和ADT的典型例子.在java中使用袋子,不需要知道袋子中数据项是如何表示的,也不需要知道袋子的操作是如何实现的吗,使用袋子的程序不依赖于这些细节.程序的这一特征就