#lang sicp
;;https://www.bilibili.com/video/BV1Xx41117tr
;;https://github.com/DeathKing/Learning-SICP/tree/master/SrtCN
;;第十一节
;;;我们不仅要关注值,也要关注时序
;;;we have to think about not only about values, but about time
;;计算一棵树种奇数的平方和
(define (sum-odd-squares tree)
(if (leaf-node? tree)
(if (odd? tree)
(square tree)
0)
(+ (sum-odd-squares (left-branch tree))
(sum-odd-squares (right-branch tree)))))
;;寻找前n个斐波那契数中的奇数
(define (odd-fibs n)
(define (next k)
(if (> k n)
'()
(let ((f (fib k)))
(if (odd? f)
(cons f (next (1+ k)))
(next (1+ k))))))
(next 1))
;;signal processing
;;;enumeriters leaves ---> filter odd? ---> map square ---> acc + 0
;;;enum interval -----> map fib ---> filter odd? ----> acc cons '()
;;;going back to this fundamental principle of computer science
;;;that in order to control something, you need the name of it
;;;流是一种数据抽象 stream is a data abstraction
;;;既然是一种数据抽象,所以先说明它的构造函数和选择函数是什么
(cons-stream x y)
(head s)
(tail s)
(head (cons-stream x y)) --> x
(tail (cons-stream x y)) --> y
;;;the-empty-stream
;;;abstraction layer
;;;abstraction barrier
(define (map-stream proc s)
(if (empty-stream? s)
the-empty-stream
(cons-stream (proc (head s))
(map-stream proc (tail s)))))
(define (filter pred s)
(cond ((empty-stream? s) the-empty-stream)
((pred (head s)) (cons-stream (head s) (filter pred
(tail s))))
(else (filter pred (tail s)))))
;;;累积函数
;;;将流中的每个元素,按照combiner累积起来
(define (accumulate combiner init-val s)
(if (empty-stream? s)
init-val
(combiner (head s)
(accumulate combiner init-val (tail s)))))
;;;将树上的叶子结点append起来,成为一个流
(define (enumerate-tree tree)
(if (leaf-node? tree)
(cons-stream tree
the-empty-stream)
(append-streams
(enumerate-tree
(left-branch tree))
(enumerate-tree
(right-branch tree)))))
;;;将两个流合并成一个流
(define (append-streams s1 s2)
(if (empty-stream? s1)
s2
(cons-stream
(head s1)
(append-streams (tail s1)
s2))))
(define (enum-interval low high)
(if (> low high)
the-empty-stream
(cons-stream
low
(enum-interval (+ 1 low) high))))
(define (sum-odd-squares tree)
(accumulate
+
0
(map square
(filter odd
(enumerate-tree tree)))))
(define (odd-fibs n)
(accumulate
cons
'()
(filter odd
(map fib
(enum-interval 1 n)))))
;;;重点:
;;;we're establishing conventional interfaces
;;;============================================================
;;;难的是accumulate
;;;map filter accumulate
;;;flatten压平,返回值为一个流
;;;一个其中的每个元素都是流的流
(define (flatten stream-of-stream)
(accumulate append-streams the-empty-stream stream-of-stream))
;;;依次对每个子流进行append
;;;((a b c ... ) (1 2 3 ... ) (A B C ... ) ... )变为
;;;(a b c ... 1 2 3 ... A B C ... ... )
;;;第一个子流s1,append第二个子流s2,append第三个子流s3,...
;;;+++++把所有的元素从子流中提取出来,把它们串接在一起+++++
;;其中f入参为一个元素,输出为一个流,也就是一个产生流的procedure
;;返回值也是一个流
(define (flatmap f s)
(flatten (map f s)))
;;;flatmap就是flatten和map的结合
;;;返回值是一个流
(collect <result> <第一个流的范围,第二个流的范围> <filter>)
;;;============================================================
;;;0<j<i<=n,并且i+j为prime
;;;将1到n中的每个数字,变成一个流
;;;1到n本身就是个流,也就是(flatmap f s)
;;;这样就变成了流的流stream-of-stream,然后传递给flatten
;;;对1到n中的每个i,生成一个流,比如i为3,即(1 2 3),则变成((3 2) (3 1))
(flatmap
(lambda (i) ;;;对每一个i进行map
(map (lambda (j) (list i j))
(enum-interval 1 (-1+ i))))
(enum-interval 1 n))
;;;(2 1)的car为2,cdr为(1),cadr为1
;;;所以这里为cadr
(filter
(lambda (p)
(prime? (+ (car p) (cadr p))))
(flatmap ... ))
(define (prime-sum-pairs n)
(map
(lambda (p)
(list (car p) (cadr p) (+ (car p) (cadr p))))
(filter ... )))
;;;总结:
;;;思路:
;;;1.将1到n的每个数字,映射为流(i j),通过(flatmap f s)
;;;2.过滤stream-of-stream中的和为prime的元素
;;;3.将结果在映射为(i j i+j)
;;;通过使用flatmap,我们可以实现其他语言中的嵌套循环
;;;by using flatmaps, we can do what would correspond to
;;;nested loops in most other languages
;;;引进collect,用来代表特定顺序的flatmap和filter操作
;;;collect is for that nest of flatmaps and filters arranged in that
;;;particular way
(define (prime-sum-pairs n)
(collect
(list i j (+ i j)) ;;;对应结果
((i (enum-interval 1 n))
(j (enum-interval 1 (-1+ i)))) ;;;对应flatmap
(prime? (+ i j)))) ;;;对应filter
;;;嵌套的flatmap
;;;八皇后问题
;;;backtracking search
;;;过于关注时间
;;;this program is too inordinately concerned with time
;;;什么是时间?时间就是step
;;;在<rest-of-positions>这些位置已经放置棋子的条件下,
;;;在<row>行<column>列放置棋子是否安全
(safe? <row> <column> <rest-of-positions>)
;;;不把这颗树看做是逐步生成的
;;;而是假设所有的东西都已经生成好了
;;;假设k-1层已经生成好了,现在要生成第k层
;;;递归策略
;;;最终结果是个流
;;;size行的前k列
(define (queens size)
(define (fill-cols k) ;;;填充第k列
(if (= k 0)
(singleton empty-board)
(collect ... )))
(fill-cols size))
(collect
(adjoin-position try-row
k
rest-queens)
((rest-queens (fill-cols (-1+ k))) ;;;k-1列的所有放置方法
(try-row (enum-interval 1 size)))
(safe? try-row k rest-queens))
;;;总结:
;;;1.编写子过程,填充第k列,(fill-cols k),是一个递归的,从第8列,到第7列,到。。。
;;;2.收集一些东西,找出k-1列的所有的放置,以及第k列的所有的可放置位置(即:1到8)
;;;3.过滤出为安全的位置
;;;最后得到结果流
;;;组合程序的方法
;;;find the second prime between 10000 and 1000000
(head
(tail
(filter prime? (enum-interval 10000 1000000))))
;;其中(enum-interval 10000 1000000)就是:
(cons 10000
(delay (enum-interval 10001 1000000)))
;;;每个盒子代表了一个集合
;;;interval filter
;;;10000 --------> prime? ------->
;;;1000000
;;;stream are not list
;;;流不是表
;;;能够增量式的计算自己,一种按需的数据结构
;;;we want to arrange for a stream to be a data structure
;;;that sorts of computes itself incrementally
;;;sort of on-demand data structure
;;;本质:数据与过程之间,并没有明显界限
;;;流就是一种用过程表示的数据,特别是tail部分
;;;tail部分是一个无参过程(lambda () ... )
(cons-stream x y) ---> (cons x (delay y))
(head s) --> (car s)
(tail s) --> (force (cdr s)) ;;;(cdr s) --> (delay y),而不是((delay y)),因为是pair,而不是list
(define (enum-interval low high)
(if (> low high)
the-empty-stream
(cons-stream
low
(enum-interval (+ 1 low) high))))
(head (tail (filter prime? (enum-interval 10000 100000000))))
;;;这部分相当于,因为low不大于high
(cons-stream 10000 (enum-interval 10001 100000000))
即:(cons 10000 (delay (enum-interval 10001 100000000)))
(filter prime? (tail (cons 10000 (delay (enum-interval 10001 100000000))))) ;;;force this promise
即:(force (delay (enum-interval 10001 100000000)))
即:(enum-interval 10001 100000000)
即:(cons-stream 10001 (enum-interval 10002 100000000))
即:(cons 10001 (delay (enum-interval 10002 100000000)))
...
直到:(cons 10009 (delay (enum-interval 10010 100000000))) 找到第一个质数
然后再找第二个
;;;delay ---> 产生一个promise
;;;即:将<exp>的立即求值,转变为lambda,因为lambda不会立即求值
(delay <exp>) ---> (lambda () <exp>)
(force p) ---> (p) ;;;p为promise
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(force p) --> (p)
(force (delay p)) ---> (p)
((delay p))
((lambda () p))
(p)
((lambda () ... )) ---> (...)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;de-couple
;;;如果一个流是通过(cons-stream a (cons-stream b ... )),不停的cons-stream得到的
;;;(tail (tail (tail ... )))
;;;修改delay的定义
(delay <exp>):
(memo-proc
(lambda ()
<exp>))
;;接受一个无参过程
(define (memo-proc proc)
(let ((already-run? nil) (result nil))
(lambda ()
(if (not already-run?)
(sequence
(set! result (proc))
(set! already-run? (not nil))
result)
result))))
;;;比如,已经知道了(tail stream)了
;;;那么,再次计算(tail (tail stream))时,内部的(tail stream)就不用再次计算了
;;;我们把数据结构组织的像一个过程
;;;we've written data structures that, in fact, are sort of like procedures.
;;;参考资料:
;;; https://github.com/xavier/sicp-notes/blob/master/lecture_06a.md
;;; https://chowdera.com/2021/11/20211129225341901Q.html
;;; https://people.eecs.berkeley.edu/~bh/ssch8/higher.html
;;; https://mitpress.mit.edu/sites/default/files/sicp/code/ch3.scm
;;;0<J<I<=N,取其中和为prime的组合
;;;将1到n的流,映射为 流的流
(flatmap
(lambda (i)
(map (lambda (j) (list i j)) (enum-interval 1 (- i 1))))
(enum-interval 1 n))
;;;过滤出其中的prime
(filter
(lambda (p)
(prime? (+ (car p) (cadr p))))
(flatmap ... ))
;;;将结果映射为(i j (i+j))
(map (lambda (x)
(list (car x) (cadr x) (+ (car x) (cadr x))))
(filter ...))
;;;改为collect的方式
(collect (list i j (+ i j))
((i (enum-interval 1 n))
(j (enum-interval 1 i)))
(prime? (+ i j)))
;;;八皇后问题
(define (queens size)
;;;递归填充第k列,k为8,7,6,。。。1,0
(define (fill-cols k)
(if (= k 0)
(singleton empty-board)
;;;收集第k列的所有可能位置
(collect ... )))
(fill-cols size))
(collect
;;;结果
(adjoin-position row k rest-queens)
;;;流
;;;1.已经存在的集合或者叫流,也就是填满第k-1列时,已经放置的位置
((rest-queens (fill-cols (- k 1)))
;;;2.row的可选集合或者叫流
(row (enum-interval 1 n)))
;;;过滤
(safe? row k rest-queens))
(cdr '(a b)) ;;;'(a b)是(list a b),而不是(cons a b)
(car '(a b))
(cdr '(x (delay y))) ;;;'(x (delay y))是(list x (delay y)),而不是(cons x (delay y))
(cdr (cons 'a 'b)) ;;; ---> b
(cdr (cons 'x (lambda () (+ 1 2))))
((cdr (cons 'x (lambda () (+ 1 2)))))
;;;https://www.thinbug.com/q/942580
;;;https://courses.cs.washington.edu/courses/cse341/04wi/lectures/14-scheme-quote.html
;;;google scheme run quote lambda
;;; pair:
;;; |--------|-------|
;;; | a | b |
;;; | | |
;;; |--------|-------|
;;;
;;;
;;; list:
;;; |------|-------| |------|---|
;;; | a | ----|------->| b | / |
;;; | | | | |/ |
;;; |------|-------| |------|---|
;;;
;;;
;;; pair:
;;; |------|-------| |------|-----|
;;; | a | ----|------->| b | c |
;;; | | | | | |
;;; |------|-------| |------|-----|
;;;
;;;
sicp-mit-11 流
于 2022-02-07 17:11:36 首次发布