Scheme 编程/Scheme 简介
现在我们已经了解了如何运行 Scheme 解释器,让我们通过一些简短的例子看看我们可以用它做什么。我们不会深入研究这些程序。目前,我们的目的是让读者对 Scheme 有一个初步的了解。
Scheme 解释器会评估用户输入的 Scheme 表达式。在我们的解释器运行后,我们首先评估一个非常简单的表达式。
> 4
4
当我们输入 '4' 并按下回车键时,我们要求我们的 Scheme 解释器评估表达式 '4'。不出所料,4 评估为 4。
接下来,我们尝试一些基本的算术运算。
> (+ 3 6)
9
> (* 18 5) ; multiplication
90
> (- 4 7)
-3
这些例子说明了 Scheme 语法中的一些重要事项。首先,语法是完全括号化的;上面表达式中的括号是必需的,不能随意添加括号,否则会改变表达式的含义。例如,以下会导致解释器报错
> ((+ 3 6))
;; Error: application of non-procedure 9
其次,我们看到 Scheme 使用前缀表示法。在每个表达式中,运算符 (+, *, -) 位于操作数(数字)之前。这与我们通常使用的数学表示法(“中缀”)不同,在中缀表示法中,运算符位于操作数之间。例如,以下不是有效的 Scheme 表达式
> (8 * 5 - 3)
;; Error: application of non-procedure 5
然而,将其转换为 Scheme 很容易
> (- (* 8 5) 3)
37
请注意,我们在这里使用表达式 (* 8 5)
作为另一个表达式的操作数!这是有效的 Scheme,我们将在所有地方看到这样的嵌套表达式。
Scheme 允许我们为值命名以便在其他表达式中使用
> (define x 20)
> x
20
> (define y (+ x 4))
> (* y 2)
48
定义 (define x 20)
使解释器将 x
定义为 20
的值。当 x
出现在定义后的代码中时,它将被此值替换。然后,我们可以在 y
的定义中使用 x
。
我们还可以定义过程。与内置运算符 +
、-
等类似,过程接受一定数量的参数(也称为参数),并计算一个值。
> (define (square x)
(* x x))
> (square 5)
25
在这里,我们定义 square
表示一个接受一个参数 x
并返回 (* x x)
值的过程。此定义的形式与我们之前看到的略有不同;在这里,定义的名称出现在括号中,后面是过程参数的名称。为了使用这个新定义的过程,我们评估 (square 5)
。
这是一个更复杂的过程,它使用 海伦公式 计算边长为 、 和 的三角形的面积
> (define (heron a b c)
(let ((s (/ (+ a b c) 2)))
(sqrt (* s (- s a) (- s b) (- s c)))))
> (heron 4 13 15)
24
在这个过程中,我们需要使用值 ,定义为
- ,
四次。如果我们要对 的每次出现都使用 (/ (+ a b c) 2)
[1],那么 heron
的定义将很繁琐且难以阅读。我们使用 let
形式来解决这个问题,它允许我们暂时将名称 s
与此值相关联。[2]
我们可以比较值,或者测试它们是否具有某些属性。
> (= 4 (+ 3 1))
#t
> (< 9 7)
#f
> (positive? 5)
#t
> (even? 5)
#f
Scheme 返回给我们的 #t
和 #f
值是什么?你可能已经猜到了,它们是分别代表“真”和“假”的布尔值。
像 positive?
这样的谓词是接受一个参数并返回布尔值的过程。在 Scheme 中,通常会给谓词取以 '?' 结尾的名称;因此,我们有 even?
、negative?
以及许多其他谓词。
过程可以是 递归 的。以下是一个经典的例子。
> (define (factorial n)
(if (= n 0)
1
(* n (factorial (- n 1)))))
> (factorial 5)
120
评估 (factorial 5)
会给出 的值,也就是 ,我们可以递归地表示为 。更一般地说,我们说 的阶乘如果 为零则为 1,否则为 乘以 的阶乘。这正是 factorial
的定义在 Scheme 语言中所述的内容
(define (factorial n)
(if (= n 0) ; is the argument 0?
1 ; then the answer is 1
(* n (factorial (- n 1))))) ; otherwise, it's n * (n - 1)!
递归是 Scheme(以及一般计算机科学)中一个重要的概念,我们将在后面的章节中更深入地讨论。
factorial
定义中的另一个新事物是使用 if
表达式,它会先评估第一个参数,然后根据第一个参数的值为真还是假,分别评估第二个或第三个参数。如果第一个参数的值为真,那么我们会得到 if
表达式的第二个参数;否则,我们会得到第三个参数。[3]
> (if #t 1 0)
1
> (if (> 2 3) 1 0)
0
练习 (解答) |
---|
|