`

计算机程序的构造和解释

 
阅读更多

 

 

 

创建一个有理数

(define (make-rat n d) (cons n d))      #定义一个分数

(define (number x) (car x))                 #number获取一个分数的分子部分

(define (denom x) (cdr x))                  #denom获取一个分数的分母部分

 

打印有理数

(define (print x)

(newline)                           #内置的基本过程,打印新的一行

(display (number x))        #打印分子部分

(display "/")                       #打印 /

(display (denom x))         #打印分母部分

 

#定义一个分数

(define one-half (make-rat 1 2))

one-half

(1 . 2)

(print one-half)                 #打印分数

 

1/2

 

 

 

可以执行加减乘除运算的 解释器

#lang racket
(define (calc exp)
   (match exp                                ; 匹配表达式的两种情况
     ((? number? x) x)                       ; 是数字,直接返回
     (`(,op ,e1 ,e2)                         ; 匹配并且提取出操作符 op 和两个操作数 e1, e2
      (let ((v1 (calc e1))                   ; 递归调用 calc 自己,得到 e1 的值
            (v2 (calc e2)))                  ; 递归调用 calc 自己,得到 e2 的值
        (match op                            ; 分支:处理操作符 op 的 4 种情况
          (`+ (+ v1 v2))                     ; 如果是加号,输出结果为 (+ v1 v2)
          (`- (- v1 v2))                     ; 如果是减号,乘号,除号,相似的处理
          (`* (* v1 v2))
          (`/ (/ v1 v2)))
        );end let
      );end (`(,op,e1,e2)
     );end match
  );end define

( calc '(+ ( + 1 2)  ( + 3 4)) )

 

定义了calc这个函数,同时也使用到了模式匹配的功能

`(op,e1,e2) 表示当前的数据结构中有三个元素,所以匹配(op,e1,e2)这三个元素

let是赋值并执行一段内容

(let (v1 值) (v2 值) (....)  (body 执行一段内容) )

这段的作用是如果匹配的是数字就返回,否则递归的求e1和e2的值,当求解完后将他们分别赋给e1和e2

最后还有一个match用于匹配op的,匹配到 加减乘法再做对应的运算 

 

 

 

#lang racket
(define env0 '())

;; 扩展。对环境 env 进行扩展,把 x 映射到 v,得到一个新的环境
(define ext-env
 (lambda (x v env)
   (cons (cons x v) env)))

;; 查找。在环境中 env 中查找 x 的值
(define lookup
            (lambda (x env)
            (let ([p (assq x env)])
               (cond
                  [(not p) x]
                    [else (cdr p)]))))

;; 闭包的数据结构定义,包含一个函数定义 f 和它定义时所在的环境
(struct Closure (f env))

;; 解释器的递归定义(接受两个参数,表达式 exp 和环境 env)
;; 共 5 种情况(变量,函数,调用,数字,算术表达式)
(define interp1
 (lambda (exp env)
   (match exp                                          ; 模式匹配 exp 的以下情况(分支)
     [(? symbol? x) (lookup x env)]                    ; 变量
     [(? number? x) x]                                 ; 数字
     [`(lambda (,x) ,e)                                ; 函数
      (Closure exp env)]
     [`(,e1 ,e2)                                       ; 调用
      (let ([v1 (interp1 e1 env)]
            [v2 (interp1 e2 env)])
        (match v1
          [(Closure `(lambda (,x) ,e) env1)
           (interp1 e (ext-env x v2 env1))]))]
     [`(,op ,e1 ,e2)                                   ; 算术表达式
      (let ([v1 (interp1 e1 env)]
            [v2 (interp1 e2 env)])
        (match op
          [‘+ (+ v1 v2)]
          [‘- (- v1 v2)]
          [‘* (* v1 v2)]
          [‘/ (/ v1 v2)]))])))


(define (interp exp)
  (interp1 exp env0)
)

(interp '(((lambda (x) (lambda (y) (* x y))) 2) 3)) 

下面表达式的计算过程

(interp '( (lambda(xx) (+ 1 xx)) 10 ) )

 

调用到match中的判断

(`(,e1 ,e2) 

这里的e1是  (lambda (xx) (+ 1 xx))

e2是  10

 

(`(,e1 ,e2))中的递归计算

[v1 (interp1 e1 env)]

[v2 (interp1 e2 env)]

 

其中 [v1 (interp1 e1 env)]

会调用到match中的判断

(`(lambda (,x) ,e) 

这里的x是 lambda函数的参数xx

e 是函数内的表达式 (+ 1 xx)

 

之后 [v2 (interp1 e2 env)]

会调用到

[(? number? x) x] 

 

之后执行到mathc v1

        (match v1

          [(Closure `(lambda (,x) ,e) env1)

           (interp1 e (ext-env x v2 env1))])

 

(interp1 e (ext-env x v2 env1))

这段的作用是计算表达式

e的值是    (+ 1 xx)

x的值是    函数的参数xx

v2的值是   10

env1的值是 ()    

(ext-env x v2 env1)

这段的作用是将

lambda的参数x(传入的参数名叫xx),还有值v2(内容是10)加入到env1环境中

此时env1是() 空的,所以执行完后env1就是(xx 10)

(+ 1 xx) ext-env最后匹配到 [`(,op ,e1 ,e2)

op是+

e1是 1

e2是xx,然后匹配到表达式 [(? symbol? x) (lookup x env)]

返回xx的值也就是10

最后计算表达式(+ 1 10) 结果为11

 

------------------------------------------------------------------------------------------------------------

 

下面表达式的计算过程

(interp '(((lambda (x) (lambda (y) (* x y))) 2) 3))

 

首先[`(,e1 ,e2)被匹配上

(let ([v1 (interp1 e1 env)]

递归执行这里的e1是

((lambda (x) (lambda (y) (* x y))) 2)

 

[v2 (interp1 e2 env)]

这里的e2是数字 3

然后匹配到 [(? number? x) x] 直接返回数字3

 

 

[v1 (interp1 e1 env)会递归调用解释器函数,最后匹配到这里

['(lambda (,x) ,e)

  (Closure exp env)]

Closure中的的exp为

    '(lambda (x) (lambda (y) (* x y)))

env为 '()

 

match匹配v1然后

(interp1 e (ext-env x v2 env1))

这里的 e是

    (lambda (y) (* x y))

x是lambda(y)中的参数y,这个表达式相当于

(interp1 '(lambda(y) (* x y)) ext-env)

这里的ext-env相当于 (x 2)

 

于是 (interp1 '(lambda(y) (* x y)) ext-env)

会继续递归,调用到[`(,e1 ,e2)

最后变成 (interp1 (* x y) ext-env)

这里的ext-env是((y 2) (x 3))

 

 

最后执行到 [`(,op ,e1 ,e2) 

这里的op 是*

e1 是 x

e2 是 y

x和y是变量,也就是匹配到表达式

[(? symbol? x) (lookup x env)] 

调用lookup函数查找key对应的value,结果x就是3,y就是2

而op匹配到 *,执行 (* 3 2)结果就是6 

 

 

 

 

 

schema官方列表

kawa官方文档

Racket官方文档

SCIP公开课翻译项目

麻省理工SCIP公开课主页

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics