【Scheme】Scheme 编程学习 (五) —— 引述
原视频地址:https://www.bilibili.com/video/BV1Kt411R7Wf?p=5
文章目录
- 【Scheme】Scheme 编程学习 (五) —— 引述
- 1. Data made from code
- empty list 空表
- 2. Treating data as code
- 3. Example: generic type safety
Quoting in Scheme, powerful way to building code, using code。
在 Scheme 中的引述,是一种强大的方式,用于构建代码,使用代码。
- Data made from code 从代码中创建数据
- Treating data as code 如何以代码的方式处理数据
- Example: generic type safety 举例:以一种通用的方式来使用类型安全
(type-safe code in a generic way)
1. Data made from code
(list "a" "b" "c")
;("a" "b" "c")
获得三个字符串组成的表
如果不创建三个字符串的表,而创建三个符号(symbol)的表呢?
(list a b c)
; reference to undefined identifier: a
失败,由于 a,b, c 为未定义的标识符,需要定义 a,b, c 。
那么如何使用储符号,而不是它们所代表的值 (not what they refer to),需要使用引述(quoting)
在 scheme 中引述,只需要使用单引号,如下:
(list 'a 'b 'c)
;(a, b, c)
我们如何嵌套这些东西 (How we can do to nest this stuff)?
(list 'a (list 'b1 'b2) 'c)
; (a (b1 b2) c)
在整个列表开始处加上单引号,也能将整个列表当作符号来处理。此种表达方式与前者等价。
'(a (b1 b2) c)
;(a (b1 b2) c)
使用引述就是告诉编译器,对这个符号什么都不要做,不去查找(look up), 只存储这个符号。
'a
;a
a
; reference to undefined indentifier: a
empty list 空表
> ()
; missing procedure expression
执行空表失败,因为需要表中至少有一项内容。
> (list)
; ()
> '()
;()
donnot execute this thing just hang out. 不执行这条语句,只是挂出来。
> null
; ()
> 'null
; null; we get back the symbol null
make data that looks like code
how we can query data
(define z 1)
(symbol? 'z)
; #t
(symbol? z)
; #f ; in this case z will be evaluated, be replaced with the value 1, and 1 is not a symbol so false
(number? 'z)
; #f
(number? z)
; #t
2. Treating data as code
将数据视为代码
(define forty-two '(* 6 9))
> forty-two
; (* 6 9) ;forty-two is a list
> (eval forty-two)
; evaluate take a list and execute for it
; 54
3. Example: generic type safety
通用类型的安全性,scheme 为弱类型语言,所以需要类型检查。示例:
检查整数
(define (safe-sum x y)(if (and (integer? x) (integer? y))(+ x y)"INCORRECT TYPES"))
定义一个过程,如果 x 和 y 都为整数,则输出执行 (+ x y) 的结果,否则输出 “INCORRECT TYPES”,示例:
> (safe-sum 1 2)
;3
> (safe-sum 1.1 2.4)
;"INCORRECT TYPES"
检查浮点数
(define (nonint? x)(and (real? x) (not (integer? x))))
; 返回 x 是否为 real 和 非integer 的与结果(define (safe-sum x y)(if (and (nonint? x) (nonint? y))(+ x y)"INCORRECT TYPES"))
; 如果 x y 都符合 nonint? 则返回 (+ x y) 的执行结果,否则返回"INCORRECT TYPES"> (safe-sum 1 2)
; "INCORRECT TYPES"
> (safe-sum 1.1 2.4)
;3.5
(define (replace lst find repl)(if (pair? lst)(cons(replace (car lst) find repl)(replace (cdr lst) find repl))(if (equal? find lst)repllst)))
此函数定义,乍看起来很难,好像又是关键字又是什么的,
其实是定义了一个函数,函数名为 replace 有三个参数,lst, find, repl,
lst - 表,
find - 期望查找的内容,
repl - 期望替换为的内容
如果表为点对则创建一个点对 cons,replace car, replace cdr 递归调用。
主干内容为,如果在 lst 中找到了 find,则返回为 repl,否则返回整个表。
使用举例
> (replace '(1 2 3) '2 "XXX")
; (1 "XXX" 3)
将表 '(1 2 3) 中的 '2 符号替换为 “XXX”
> (replace '(a (b1 b2) c) 'b1 'BOO)
; (a (BOO b2) c)
将表 '(a (b1 b2) c) 中的 'b1 符号替换为 'BOO 符号
前面定义了两种类型安全的和计算 safe-sum
这里我们可以定义一个通用类型的函数
(define generic-safe-sum; an quoted expression'(define (safe-sum x y)(if (and (TEST x) (TEST y))(+ x y)"INCORRECT TYPES")))
与前两者基本类型,不同的地方为,这里我们定义 TEST 为一个通用类型的检查。注意 函数定义之前有个(quoting)引述 ‘ ,所以在定义时,这部分代码都被视作符号不进行执行 (evaluate)。
如果我们想知道 generic-safe-sum 的内容,则会完整的输出这个引述的表达式。
> generic-safe-sum
; (define (safe-sum x y)
; (if (and (TEST x) (TEST y))
; (+ x y)
; "INCORRECT TYPES"))
然后我们定义一个整数类型检查并查看
> (define safe-sum-q(replace generic-safe-sum 'TEST 'integer?)) ; 将通用类型的检查替换为 整数检查
> safe-sum-q
; (define (safe-sum x y)
; (if (and (integer? x) (integer? y))
; (+ x y)
; "INCORRECT TYPES"))
与原 generic-safe-sum 几乎一致,除了 TEST 被替换为了 integer?,仍然是一个完整的引述表达式。
safe-sum-q 为一个表,不为函数,只有 evaluate (eval) 时才会执行。
> (eval safe-sum-q)
; 执行safe-sum-q,这里我们定义了一个函数 safe-sum
; (define (safe-sum x y)
; (if (and (integer? x) (integer? y))
; (+ x y)
; "INCORRECT TYPES"))
> (safe-sum 1 2)
; 3
> (safe-sum 1.1 2.4)
; "INCORRECT TYPES"
本节通过示例,我们更清晰的知道了引述的用途,以及使用的方法。