# 斯坦福编程范式 CS107_21
# 将之前 C++ 写的一个函数用 Scheme 编程
使用 scheme 实现如下内容:
>(double-all '(1 2 3 4)) | |
(2 4 6 8) | |
>(incr-all '(1 2 3 4)) | |
(2 3 4 5) |
对于这种功能,不需要迭代,只需要如下代码就可以实现:
(define (double x)(* x 2)) | |
(define (incr x)(+ x 1)) |
在 scheme 中还有一个内置函数被称为 Map,它可以接收 2 个或多个参数,并且它的第一个参数可以是之前定义好的函数的名字,第二个参数是你要连接的列表。如下所示。map 是递归的对参数列表中的每一个元素进行相应的函数操作。
>(map double '(1 2 3 4)) | |
(2 4 6 8) | |
>(map incr '(1 2 3 4)) | |
(2 3 4 5) | |
>(map car '((1 2) (4 8 2) (11))) | |
(1 4 11) | |
>(map cdr '((1 2) (4 8 2) (11))) | |
((2) (8 2) ()) |
使用 map 函数处理多元参数的函数。如 cons,那么我们需要提供两个列表,第一个列表中的元素都是 cons 的第一个参数,第二个列表中的元素都是 cons 的第二个参数。
>(map cons '(1 2 8) '((4) () (2 5))) | |
((1 4) (2) (8 2 5)) | |
>(map + '(1 2) '(3 4) '(6 10)) | |
(10 16) |
假设你传入的参数比如列表长度不一致,map 也不会生气,它会在最短的对齐结束后就结束运行。
>(map + '(1 2) '(3 4 1) '(6 10)) | |
(10 16) |
# 下面来实现这样的一个 map 函数
(define (my-unary-map fn seq) | |
(if (null? seq) '() | |
(cons (fn (car seq)) | |
(my-unary-map fn (cdr seq))))) |
# eval 函数和 apply 函数
# eval
eval 函数是每次你写好 scheme 语句后,敲回车都会执行的函数。它的作用如下所示。
>'(+ 1 2 3) | |
(+ 1 2 3) | |
>(eval '(+ 1 2 3)) | |
6 |
eval 的应用场景一般是 apply 无法使用的时候,apply 后面无法跟 define、and、or 这一类特殊的函数。
# apply
apply 和 eval 的区别在于,apply 允许你指定用哪一个函数来处理后面的那些参数。
>(apply + '(1 2 3)) | |
6 |
让我们使用 apply 写一个计算所有数字平均值的函数。假设都是 double 类型的,那样就不需要去处理小数点之类的问题:
(define (average num-list) | |
(/ (apply + num-list) | |
(length num-listt))) |
# 使用 map 和 apply 来消除嵌套列表问题
((1 2) ((3) ((4) 5)) 10) |
如果传入的参数不是一个列表,那么我们就把它单独放在一个列表中,便于后面我们使用 append 对所有列表进行拼接。后面的是一个递归使用,其中 map flatten seq 递归到最后应该是多个列表,我们再使用 apply 强行将 append 安排在这些列表的最前面,形成了 append '(1 2) '(3 4 5) '(10)
这样的结构,最终合成一个列表 '(1 2 3 4 5 10)
(define (flatten seq) | |
(if(not (list? seq) (list seq)) | |
(apply append | |
(map flatten seq)))) |
# 构建一个广义翻译的函数
作用:我们希望它能接收一个参数长度为 n 的一个列表,然后产生另一个 n 个点的列表,每个点都偏移了 delta 的量。
>(translate '(2 5 8 11 25) 100) | |
(102 105 108 111 125) |
构造:通过 lambda 构造了一个匿名函数,在这个函数中,对 points 的每一个元素都 + delta 值。lambda 函数已经很熟悉了,可以参考知乎的文章。
(define (translate points delta) | |
(map (lambda(x) (+ x delta)) ponits)) |
上述函数等价于
(define (translate seq delta) | |
(define (shift-by x) | |
(+ x delta)) | |
(map shift-by seq)) |
lambda 函数的简单例子和它的等价形式:在使用 lambda 函数后,我们就可以更清晰的明白 sum
实际上是可以直接替换成 lambda(x y)(+ x y)
的,而这也是 scheme 中其他函数在被使用时真正的使用过程。即简单的符号替换。
(define (sum x y) | |
(+ x y)) | |
================== | |
(define sum | |
(lambda(x y)(+ x y))) |
Scheme 语言全是关于符号的,符号评估,函数评估。