• Racket, SICP stream learning


    在 windows 上重新安装了最新的 Racket 5.2.1.

    恍然发现,Common-Lisp 的安装真的比较坑爹啊,Racket 可能才是研究和学习 lisp 比较理想的选择!

    不管是 Windows 还是 Ubuntu,自学习 Lisp 以来,Common Lisp 的各种实现 + 开发环境也安装了很多了,每一个配置起来都比较麻烦,也都有这样那样的问题。而相比而言,安装 Racket 却超级傻瓜化。

    一番周折后,终于调通了 SICP 220 页开始的对于 stream 的一些示例代码。其中需要注意的是:

    书中提到的 cons-stream 是一个 special form, 但是我一开始写成了简单的 function 如下:

    ; this won't work as a simple function
    (define (cons-stream a b)
        (cons a (delay b)))

    但这个实际是是不 work 的。如果流比较大或者是无限流,几乎一定会导致无限递归、内存溢出。解决的办法参考了 stack overflow 上一个答案,利用 Racket 的 define-syntax 语法定义宏。其实和 Common Lisp 里宏有点接近,只是定义时使用的语法有差异,用到方括号,详见代码。

    和 Common Lisp 中列表的 subseq 函数相似,我简单的实现了一个 stream-subseq 函数,用于截取流中某一区间的子序列,配合 display-stream 函数打印会比较方便的了解流中间任意一段的信息,后面的测试输出代码我基本都这么写了。

    通过无限流移位后相加、相乘甚至配合其他运算进行任意组合,是流使用起来感觉最妙的地方。代码中包含了 SICP 原书中附带的一个筛法求素数序列的实现。

    通过几个例子简单的试验下来发现,的确 stream 的功效是强大的。因为本质上每一步计算都是惰性求值,所以即使是要估算序列中很后面的数值,也不会像列表那样带来很多分配空间的开销。斐波那契数列可以轻而易举的算到很后面。下面是我调试通过的测试代码:

    #lang racket
    
    ;(define (delay exp)
    ;  (lambda () exp))
    ;  ;(memo-proc (lambda ()
    ;  ; exp)))
    ;
    ;(define (force delayed-object)
    ;  (delayed-object))
    ;
    ;(define (memo-proc proc)
    ;  (let ((already-run? false) (result false))
    ;    (lambda ()
    ;      (if (not already-run?)
    ;          (begin (set! result (proc))
    ;                 (set! already-run? true)
    ;                 result)
    ;          result))))
    
    (define (stream-car stream) (car stream))
    
    (define (stream-cdr stream) (force (cdr stream)))
    
    ; this won't work as a simple function
    ;(define (cons-stream a b)
    ;  (cons a (delay b)))
    
    ; This is scheme syntax for macro
    ; http://stackoverflow.com/questions/5610480/scheme-sicp-r5rs-why-is-delay-not-a-special-form
    (define-syntax cons-stream
      (syntax-rules ()
        [(cons-stream x y) (cons x (delay y))]))
    
    (define the-empty-stream '())
    
    (define (stream-null? stream)
      (null? stream))
    
    (define (stream-filter pred stream)
      (cond ((stream-null? stream) the-empty-stream)
            ((pred (stream-car stream))
             (cons-stream (stream-car stream)
                          (stream-filter pred (stream-cdr stream))))
            (else (stream-filter pred (stream-cdr stream)))))
    
    (define (stream-ref s n)
      (if (stream-null? s) the-empty-stream
          (if (= n 0)
              (stream-car s)
              (stream-ref (stream-cdr s) (- n 1)))))
    
    (define (stream-map proc . argstreams)
      (if (stream-null? (car argstreams))
          the-empty-stream
          (cons-stream (apply proc (map stream-car argstreams))
                       (apply stream-map 
                              (cons proc (map stream-cdr argstreams))))))
    
    (define (stream-for-each proc s)
      (if (stream-null? s)
          'done
          (begin (proc (stream-car s))
                 (stream-for-each proc (stream-cdr s)))))
    
    ; Neil, 2012-05-10
    (define (stream-subseq stream a b)
      (cond ((stream-null? stream) the-empty-stream)
            ((= a b) the-empty-stream)
            ((> a b) the-empty-stream)
            (else (cons-stream (stream-ref stream a)
                  (stream-subseq stream (+ a 1) b)))))
    
    (define (display-line x)
      (newline)
      (display x))
    
    (define (display-stream s)
      (stream-for-each display-line s))
    
    ; examples
    ;(let ((x (delay (+ 1 2))))
    ;  (for ([i (in-range 1 10)])
    ;            (display (force x))))
    ;
    (define (integers-starting-from n)
      (cons-stream n (integers-starting-from (+ n 1))))
    
    (define integers
      (integers-starting-from 1))
    
    ;(display-line (stream-ref integers 0))
    (let ((x (stream-subseq integers 10000 10010)))
      (display-stream x))
    
    (define odd-numbers 
      (stream-filter odd? integers))
    
    (display-stream (stream-subseq odd-numbers 50 60))
      
    ;(let ((x (cons-stream 1 (cons-stream 2 '(3)))))
    ;  (display-stream x))
    
    (define (stream-add s n)
      (stream-map (lambda (x)
                    (+ x n)) s))
    
    (define (add-streams s1 s2)
      (stream-map + s1 s2))
    
    (define fib
      (cons-stream 1
                   (cons-stream 1
                                (add-streams fib
                                            (stream-cdr fib)))))
    
    (display-stream (stream-subseq fib 150 160))
    
    
    (define (divisible? x y)
      (= (remainder x y) 0))
    
    (divisible? 10 2)
    
    (define (sieve stream)
      (cons-stream
       (stream-car stream)
       (sieve (stream-filter
               (lambda (x)
                 (not (divisible? x (stream-car stream))))
               (stream-cdr stream)))))
    
    (define primes
      (sieve (integers-starting-from 2)))
    
    (display-stream (stream-subseq primes 1000 1010))

    接下来打算认真体会一下书中提到的欧拉发明的序列加速器的算法。真的是很厉害的 idea.

  • 相关阅读:
    过滤器--起步阶段
    常用指令-起步阶段
    模型和控制器-起步阶段
    指令介绍-起步阶段
    AngularJS简介-起步阶段
    c++之helloworld与命名空间
    c++ 之重要性
    一个没曾摸透的程序
    linux中什么是文件结构体?
    很全的linux网络编程技巧
  • 原文地址:https://www.cnblogs.com/RChen/p/2495281.html
Copyright © 2020-2023  润新知