Scheme
Scheme,一种多范型的编程语言,它是两种Lisp的一个现代变种。它是由Guy L. Steele跟Gerald Jay Sussman在1970年代发展出来。Scheme也是第一个使用静态而非动态变量区域的Lisp方言。Scheme的哲学思想是:设计计算机语言不应该进行功能(feature)的堆砌,而应该尽可能减少弱点(weakness)和限制(restriction),使剩下的功能显得必要。Scheme语言的规范很短,总共只有50页,甚至连Common Lisp 规范的索引的长度都不到,但是却被称为是现代编程语言王国的皇后。它与以前和以后的 Lisp 实现版本都存在一些差异,但是却易学易用。
Scheme的一个主要特性是可以像操作数据一样操作函数调用。Scheme 是 MIT 在70年代创造出来,其的主要目的是训练人的机器化思维。以其简洁的语言环境和大量的脑力思考而著称。
正由于lisp语言的历史悠久,所以最初接触scheme的语法,我们常会感到一头雾水。但是这种语言自有它独特的魅力。
Scheme特点[ ]
- 括号嵌套
Lisp 程序中充满了一对对嵌套的小括号,这些嵌套的符号体现了最基本的数学思想——递归。
- 语法简洁
Scheme语言的规范很短,总共只有50页。
- 函数编程语言
一个函数(Function)是这个编程语言中所谓的第一等的公民。也就是说函式可以像一个 int 或者 float 一样被很方便的传递来传递去。这也就是所谓“Functional 编程语言”中,Functional 一词的由来。
- 自动内存管理
自动内存管理可不是JAVA的专利,Scheme也享有自动内存管理机制。
- 支持尾递归
- 提高了递归效率
支持高级控制结构continuation
- 可移植性好
Scheme开发的程序有很好的可移植性,这是由于Scheme是一种解释语言,在不同的平台都可以有相应的解释器。
- 适合作为脚本语言和嵌入语言
由于scheme语法简洁,一个Scheme解释器可以非常的小巧。Scheme可以作为脚本语言而内嵌于一些工具之中,如:GNU Emacs。
- 关键字对大小写不敏感
Scheme数据结构[ ]
- 数字
下面都是合法的数字表示方法:47,1/3,2.3,4.3e14,1+3i。
- 字符
字符前面需要用#\做前缀。如下面都是合法字符:
#\a #\A #\b #\B #\space #\newline
由双引号括起来的字符组成字符串。如:"A little string"
- 布尔值
布尔值True和False分别用 #t 和 #f 表示。
- 列表
用圆括号括起来的,可以包含任何数据类型的称为列表。如: (a little (list of) (lists))
- 数组(vector)
用#为前缀,如: #(1 2 "string" #\x 5)
- 函数(或称为过程)
把函数作为一种数据类型,是Scheme语言的特色。
- 符号
符号除了不能够以数字开头的任何字符可组成符号。如:Symbols: this-is-a-symbol foo a32 c$23*4&7+3-is-a-symbol-too!
Scheme注释[ ]
分号开始一段注释。如:
(+ 3 1) ; return 4
Scheme常量表达式[ ]
常量表达式返回本身的值。如:
3.14 ; 返回 3.14 #t ; 返回布尔值 #t #\c ; 返回字符 #\c "Hi!" ; 返回字符串 "Hi!"
Scheme引用(Quotation)[ ]
语法: (quote obj) 或者简写为 'obj (+ 2 3) ; 返回 5 '(+ 2 3) ; 返回列表 (+ 2 3) (quote (+ 2 3)) ; 返回列表 (+ 2 3)
Scheme表达式记法[ ]
Scheme的表达式的写法有些特别,表达式用括号括起来。括号里面的第一个出线的是函数名或者操作符,其它是参数。Scheme的这种表达式写法可以叫做前置式。下面是一些Scheme的表达式的例子以及其对应的C语言的写法。
Scheme C ------------------------------------------------------------------ (+ 2 3 4) (2 + 3 + 4) (< low x high) ((low < x) && (x < high)) (+ (* 2 3) (* 4 5)) ((2 * 3) + (4 * 5)) (f x y) f(x, y) (define (sq x) (* x x)) int sq(int x) { return (x * x) }
Scheme对象绑定、赋值和函数定义[ ]
let 表达式语法糖果
语法: (let ((var val) ...) exp1 exp2 ...)
说明:let 表达式是 lambda 表达式的语法糖果,即:(let ((var val) ...) exp1 exp2 ...),为 ((lambda (var ...) exp1 exp2) val ...)
- 示例:
(let ((x 2) (y 3)) (+ x y))
- 先绑定: x=2, y=3,再计算x+y的值,结果为5。注意 (x 2) 和 (y 3) 外还有一层括号。
- 更多的示例:
(let ((f +)) (f 2 3)) ; return 5 (let ((f +) (x 2)) (f x 3)) ; return 5 (let ((f +) (x 2) (y 3)) (f x y)) ; return 5
- 用 define 绑定对象和 set! 赋值
- 语法:(define var exp) , (set! var exp)
- 说明:define绑定的对象在当前作用域中有效。define 和 set! 的区别是define既能赋值又能定义变量,而set!只能对已经定义的变量赋值。
- 示例:
(define a 1) a ; return 1 (set! a 2) a ; return 2 (let ((a 3)) a) ; return 3 a ; return 2 (let ((a 3)) (set! a 4) a) ; return 4 a ; return 2 (let ((a 3)) (define a 5) a) ; return 5 a ; return 2 (set! b 1) ; 错误,b尚未定义
- lambda 表达式和函数定义
- 语法:(lambda (var ...) exp1 exp2 ...)
- 说明:lambda 表达式用于定义函数。var ... 是参数,exp1 exp2 ...是函数的执行 部分。通常需要结合局部定义 let 或者全局定义表达式 define,再进行函数调用。
- 示例:
((lambda (x) (+ x x)) (* 3 4)) ; return 24
- 说明:先用lambda定义了函数,参数是x,函数返回x+x。同时该语句也完成了函数调用,实参是 12 (等于3*4),因此返回值是 24 (等于12+12)。
在let表达式中定义函数。
Scheme语言中,函数作为一种数据类型,通过赋值语句,将lambda表达式赋值给相应的函数。
- 示例:
(let ((double (lambda (x) (+ x x)))) (list (double (* 3 4)) (double (/ 99 11)) (double (- 2 7)))) ; return (24 18 -10)
- 说明:let表达式将lambda定义的函数赋值给double,参数是x,返回 x+x。接下来分别三次调用 double 函数,并将结果以列表形式返回。list 表达式负责生成列表。
用define全局定义表达式来定义函数。
用 let 定义的函数只能在 let 表达式中有效,如果想定义在整个程序中有效的函数定义,需要用到全局定义表达式——define。
- 示例:
(define double (lambda (x) (+ x x))) (double 12) ; return 24 (double (* 3 4)) ; return 24
- 说明:define表达式定义了全局有效的函数 double。两次调用double的返回值都是 24。
定义函数的简写
用 define 定义的函数的语法可以简化,即将 lambda 去掉。即将语法
(define var0 (lambda (var1 ... varn) e1 e2 ...)) 简写为: (define (var0 var1 ... varn) e1 e2 ...)
- 示例:
(define (double x) (+ x x)) (double 12) ; return 24 (double (* 3 4)) ; return 24
- 说明:本例是前一个例子的简化版本。更简介,明了。
Scheme顺序计算表达式[ ]
- 语法:(begin exp1 exp2 ...)
- 说明:顺序执行表达式 exp1, exp2, ...,返回最后一个表达式的结果
- 示例:
(define x 3) (begin (set! x (+ x 1)) (+ x x)) ; 返回结果 8
- 说明:begin 表达式,依次先用set!表达式为x赋值为4,在运算x+x,返回结果8。
主要的Scheme环境有:MIT Scheme、DrScheme