[SICP Notes] 1.1 The Elements of Programming

1 篇文章 0 订阅
1 篇文章 0 订阅

About the Book

To know more about programming, I have decided to start reading the famous Structure and Interpretation of Computer Programs (SICP, or the Wizard Book), which is first published by MIT in 1985. The Wizard Book used MIT Scheme, which is a dialect of Lisp, as the demonstrating language. This language is so different from the languages I know (C++ and JavaScript, which are both inspired by C). However, the book does not talk much about the characteristics of the language. It focus on teaching important concepts in Computer Science, but not teaching a particular language. I am sure that the book and the interesting language can help me to become a better programmer! (but not just a coder XD) This book is available online under Creative Common (CC) so you may take a look at it too!


Important Quotes from the Book

1.1.3  Evaluating Combinations


To evaluate a combination, do the following:
  1. Evaluate the subexpressions of the combination. (recursively!)
  2. Apply the procedure that is the value of the leftmost subexpression (the operator) to the arguments that are the values of the other subexpressions (the operands).
We take care of the primitive cases by stipulating that
  • the values of numerals are the numbers that they name,
  • the values of built-in operators are the machine instruction sequences that carry out the corresponding operations, and
  • the values of other names are the objects associated with those names in the environment.


1.1.5  Applicative Order Versus Normal Order


The evaluation model used in Lisp first evaluates the operator and operands and then applies the resulting procedure to the resulting arguments. This ``evaluate the arguments and then apply'' method is called applicative-order evaluation.

An alternative evaluation model would not evaluate the operands until their values were needed. Instead it would first substitute operand expressions for parameters until it obtained an expression involving only primitive operators, and would then perform the evaluation. This alternative ``fully expand and then reduce'' evaluation method is known as normal-order evaluation.


1.1.7  Mathematical Functions Versus Computer Procedures


The contrast between function and procedure is a reflection of the general distinction between describing properties of things and describing how to do things, or, as it is sometimes referred to, the distinction between declarative knowledge and imperative knowledge. In mathematics we are usually concerned with declarative (what is) descriptions, whereas in computer science we are usually concerned with imperative (how to) descriptions.


1.1.8  Procedures as Black-Box Abstractions


For example, when we define the good-enough? procedure in terms of square, we are able to regard the square procedure as a ``black box.'' We are not at that moment concerned with how the procedure computes its result, only with the fact that it computes the square. The details of how the square is computed can be suppressed, to be considered at a later time. Indeed, as far as the good-enough? procedure is concerned, square is not quite a procedure but rather an abstraction of a procedure, a so-called procedural abstraction. At this level of abstraction, any procedure that computes the square is equally good.

Local names

A formal parameter of a procedure has a very special role in the procedure definition, in that it doesn't matter what name the formal parameter has. Such a name is called a bound variable, and we say that the procedure definition binds its formal parameters. The meaning of a procedure definition is unchanged if a bound variable is consistently renamed throughout the definition. If a variable is not bound, we say that it is free. The set of expressions for which a binding defines a name is called the scope of that name. In a procedure definition, the bound variables declared as the formal parameters of the procedure have the body of the procedure as their scope.

Internal definitions and block structure

Lexical scoping dictates that free variables in a procedure are taken to refer to bindings made by enclosing procedure definitions; that is, they are looked up in the environment in which the procedure was defined.

In lexical scoping (or lexical scope; also called static scoping or static scope), if a variable name's scope is a certain function, then its scope is the program text of the function definition: within that text, the variable name exists, and is bound to the variable's value, but outside that text, the variable name does not exist. By contrast, in dynamic scoping (or dynamic scope), if a variable name's scope is a certain function, then its scope is the time-period during which the function is executing: while the function is running, the variable name exists, and is bound to its variable, but after the function returns, the variable name does not exist. This means that if function f invokes a separately defined function g, then under lexical scoping, function g does not have access to f's local variables (since the text of g is not inside the text of f), while under dynamic scoping, function g does have access to f's local variables (since the invocation of g is inside the invocation of f).
(Source: Wikipedia)


My Solution to the Exercises


Exercise 1.1

In this exercise, I only need to write down the result of each expression. I have put a semi-colon(;) before the result.

10
;10
(+ 5 3 4)
;12
(- 9 1)
;8
(/ 6 2)
;3
(+ (* 2 4) (- 4 6))
;6
(define a 3)
(define b (+ a 1))
(+ a b (* a b))
;19
(= a b)
;#f
(if (and (> b a) (< b (* a b)))
    b
    a)
;4
(cond ((= a 4) 6)
      ((= b 4) (+ 6 7 a))
      (else 25))
;16
(+ 2 (if (> b a) b a))
;6
(* (cond ((> a b) a)
         ((< a b) b)
         (else -1))
   (+ a 1)
;16

Exercise 1.2

In this exercise, I need to translate a mathematical expression into a complex combination in Scheme.

(/ (+ 5
      4
      (- 2
	 (- 3
	    (+ 6
	       (/ 4 3)))))
   (* 3
      (- 6 2)
      (- 2 7)))
(well, I have abused the use of indentation in this exercise...)

Exercise 1.3

In this exercise, I need to write a procedure that take three numbers as arguments and returns the sum of the squares of the two larger numbers.

(define (sum-of-squares-of-larger-two a b c)
  (cond ((and (<= a b) (<= a c)) (+ (* b b) (* c c)))
		((and (<= b a) (<= b c)) (+ (* a a) (* c c)))
		(else (+ (* a a) (* b b)))))

Exercise 1.4

In this exercise, I need to explain the behaviour of the following procedure:

(define (a-plus-abs-b a b)
  ((if (> b 0) + -) a b))
This procedure returns the sum of a and the absolute value of b.

When b is positive, the procedure return a+b.
When b is 0 or negative, the procedure returns a-b (a-b = a-(-|b|) = a+|b|, given b<=0)

Exercise 1.5

Given the following code, is the result different when applicative order and normal order are used?

(define (p) (p))

(define (test x y)
  (if (= x 0)
      0
      y))

(test 0 (p))

Applicative Order:

(test 0 (p))

This method would first evaluate all the subexpressions of the combination.
(p) calls (p) again so there is an infinite loop. (runtime_error)

Normal Order:

(test 0 (p))
(if (= 0 0) 0 (p))
0

This method would first substitute operand expressions for parameters until it obtained an expression involving only primitive operators, and would then perform the evaluation. (p) is not evaluated until it is needed, so no infinite loop appears. (0 is returned)


Exercise 1.6

Why the built-in if is a special form instead of a procedure? Given the following definition of a new-if:

(define (new-if predicate then-clause else-clause)
  (cond (predicate then-clause)
        (else else-clause)))
This new-if looks pretty good when applying to simple cases. However, it is not that good when recursion is used in the clauses. Consider this:

(define (sqrt-iter guess x)
  (new-if (good-enough? guess x)
          guess
          (sqrt-iter (improve guess x)
                     x)))
Since the interpreter evaluate combinations in applicative order, it would evaluate all the subexpressions in (new-if predicate then-clause else-clause). As the else-clause of new-if in sqrt-iter is sqrt-iter itself, using new-if would invoke an infinite loop.

If the special form if is used instead, the interpreter would not evaluate both the then-clause and else-clause. The self-calling then clause is only evaluated when predicate returns false.

Exercise 1.7

In the sample (sqrt x) procedure in this chapter, a good-enough procedure is used to judge whether the approximation of the sqrt is accurate enough:

(define (good-enough? guess x)
  (< (abs (- (square guess) x)) 0.001))
We say that the guess is good enough if the difference between guess square and x is fewer than a value, 0.001 here. However, this method has its limitation. When x is very big or very small, the fixed value of 0.001 cannot play its role effectively. (you can try!) So I write a new procedure for this exercise:

(define (average x y)
  (/ (+ x y) 2.0))

(define (square x) (* x x))

(define (sqrt x)
  (define (good-enough? guess old-guess)
    (< (abs (/ (- guess old-guess)
            old-guess))
       0.00000001))
  (define (improve guess)
    (average guess (/ x guess)))
  (define (sqrt-iter guess old-guess)
    (if (good-enough? guess old-guess)
        guess
        (sqrt-iter (improve guess)
                   guess)))
  (sqrt-iter 1.0 -1.0))
Notice that I have put procedures like good-enough? and improve into the definition of sqrt. Doing so can reduce confusion (as good-enough? and guess are common names but should only be useful in the sqrt procedure) and reduce the number of parameters in each procedure (x needs not to be passed due to its lexical scope).


Exercise 1.8

This one is similar to 1.7 but this time I am solving for the cube root.

(define (pow x y)
  (if (= y 0)
      1
      (* x (pow x (- y 1)))))

(define (cube-root x)
  (define (good-enough? guess old-guess)
    (< (abs (/ (- guess old-guess)
               old-guess))
       0.00000001))
  (define (improve guess)
    (/ (+ (/ x (pow guess 2))
          (* 2 guess))
       3))
  (define (cube-root-iter guess old-guess)
    (if (good-enough? guess old-guess)
        guess
        (cube-root-iter (improve guess)
                        guess)))
  (cube-root-iter 1.0 -1.0))

(cube-root -8)
I have added a test case -8 to show that this procedure can handle the negative root as well.


Do you find coding in Scheme interesting? Or are you interested in the Wizard Book? Join me to read the book so that we can share our thoughts!

【6层】一字型框架办公楼(含建筑结构图、计算书) 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值