UP | HOME

分支

Table of Contents

本章中会讲解如何通过 条件 编写过程。这个是编写使用程序很重要的一步

if 表达式

if 表达式将过程分为两个部分。格式如下:

(if predicate then-value else-value)

如果 predicate 部分为 ,那么 then-value 部分 被求值 ,否则 else-value 部分被 求值 ,并且 求得的值返回if语句的括号外

true 是除 false 以外的任意值:

  • true 使用 #t 表示
  • false#f 表示
    在R5RS中,false #f 和空表 '() 是两个不同的对象

    然而,在MIT-Scheme中,这两个为同一对象

    这个不同可能是历史遗留问题,在以前的标准R4RS中,#f 和 '() 被定义为同一对象

从兼容性角度考虑, 不应该使用表目录作为谓词 。使用函数 null? 来判断 表是否为空

(null? '()) ; #t 

(null? '(a b c)) ; #f 

if 表达式是一个 特殊形式 ,因为它 不对所有的参数求值

  • 如果 predicate 为真,则只有 then-value 部分被求值
  • 如果 predicate 为假,只有 else-value 部分被求值

例,首项为 a0,增长率 r,项数为 n 的几何增长数列之和:

(define (sum-gp a0 r n)
  (* a0
     (if (= r 1)
         n
         (/ (- 1 (expt r n)) (- 1 r)))))   ; !!
通常来说,几何增长数列的求和公式如下:

a0 * (1 - r^n) / (1 - r)                      (r ≠ 1)
a0 * n                                               (r = 1)

如果 if 表达式对所有参数求值的话,那么有 ;!! 注释的那行就算在 r = 1 时也会被求值,这将导致产生一个 除数为0 的错误

可以省去 else-value 项。当 predicate 为假时, 返回值就没有被指定 。如果你希望当predicate为假时返回 #f ,那么就要明确地将它写出来

then-value 和 else-value 都应该是 S-表达式

如果你需要副作用 ,那么就应该使用 begin 表达式

复合逻辑

not

函数 not 可用于对 谓词取反 :此函数只有 一个参数

  • 如果参数值为 #f 则返回 #t
  • 参数值为 #t 则返回 #f

and

and 具有 任意个数的参数 ,并从左到右对它们求值:

  • 如果某一参数为 #f ,那么它就返回 #f ,而 不对剩余参数求值
  • 如果所有的参数都不是 #f ,那么就返回 最后一个参数的值
(and #f 0) ; #f
(and 1 2 3) ; #3 
(and 1 2 3 #f) ; #f 

or

or 具有 可变个数的参数 ,并从左到右对它们求值:

  • 它返回第一个 不是值#f的参数 ,而 余下的参数不会被求值
  • 如果 所有的参数的值都是 #f 的话,则返回 #f
(or #f 0) ;  0 
(or 1 2 3) ; 1
(or #f 1 2 3) ; 1 
(or #f #f #f) ; #f
and 和 or 是用于组合条件的两个特殊形式

Scheme中的and和or不同于C语言中的约定
   它们不返回一个布尔值(#t 或 #f)
   而是返回给定的参数之一

and和or可以使你的代码更加短小

cond 表达式

    尽管所有的分支都可以用 if表达式 表达

    但当条件有更多的可能性时,就需要使用嵌套的if表达式了,这将使代码变得复杂

处理这种情况可以使用 cond表达式 。cond表达式的格式如下:

(cond
  (predicate-1 clauses-1)
  (predicate-2 clauses-2)
    ......
  (predicate-n clauses-n)
  (else        clauses-else))

cond表达式 中, predicates-i 是按照 从上到下 的顺序求值:

  • predicates-i 时, clause-i 会被 求值并返回
  • i 之后的 predicatesclauses 不会被求值
  • 如果所有的 predicates-i 都是 的话,则返回 cluase-else

在一个子句中,可以写数条S-表达式,而 clause 的值是 最后一条 S-表达式

例:城市游泳池的收费。

Foo市的城市游泳池按照顾客的年龄收费:

如果 age ≤ 3 或者 age ≥ 65 则 免费;
如果 介于 4 ≤ age ≤ 6 则 0.5美元;
如果 介于 7 ≤ age ≤ 12 则 1.0美元;
如果 介于 13 ≤ age ≤ 15 则 1.5美元;
如果 介于 16 ≤ age ≤ 18 则 1.8美元;
其它 则 2.0美元;

那么,一个返回城市游泳池收费的函数如下:

(define (fee age)
  (cond
   ((or (<= age 3) (>= age 65)) 0)
   ((<= 4 age 6) 0.5)
   ((<= 7 age 12) 1.0)
   ((<= 13 age 15) 1.5)
   ((<= 16 age 18) 1.8)
   (else 2.0)))

谓词函数

这里将介绍一些用于做判断的函数。这些函数的名字都以 '?' 结尾

eq?、eqv?和equal?

基本函数 eq?eqv?equal? 具有 两个参数 ,用于检查 这两个参数是否“一致” 。这三个函数之间略微有些区别:

eq? 用来比较两个是否是 同一个对象 (指向的地址是否相同)

     例如,(eq? str str) 返回 #t,因为str本身的地址是一致的

     与此相对的,因为字符串 "hello" 和 "hello" 被储存在了不同的地址中,函数将返回 #f

     不要使用eq?来比较数字,因为不仅在R5RS中,甚至在MIT-Scheme实现中,它都没有指定返回值

     使用eqv?或者=来比较数值
(define str "hello")

(eq? str str) ; #t 
(eq? "hello" "hello") ; #f

;;; comparing numbers depends on implementations
(eq? 1 1) ; #t 
(eq? 1.0 1.0) ; #f 

eqv? 该函数比较两个存储在内存中的 对象的类型 和 值 。如果类型和值都一致的话就返回 #t

eq? 一样,但相同的数字会被认为一样

对于过程(lambda表达式)的比较依赖于具体的实现

这个函数不能用于类似于 表 和 字符串 一类的序列比较,因为尽管这些序列看起来是一致的,但它们的值是存储在不同的地址中
(eqv? 1.0 1.0) ; #t 
(eqv? 1 1.0) ; #f 

;;; don't use it to compare sequences
(eqv? (list 1 2 3) (list 1 2 3)) ; #f 

(eqv? "hello" "hello") ; #f 

;;; the following depends on implementations
(eqv? (lambda(x) x) (lambda (x) x)) ; #f 

equal? 函数用于比较类似于 或者 字符串 一类的序列

     不仅比较值,还会深层地比较变量的数据结构
(equal? (list 1 2 3) (list 1 2 3)) ; #t 
(equal? "hello" "hello") ; #t 

检查数据类型

下面列举了几个用于 检查类型 的函数。这些函数都只有 一个参数

  • pair? 如果对象为 序对 则返回 #t
  • list? 如果对象是一个 则返回 #t
  • null? 如果对象是 空表 '() 的话就返回 #t
  • symbol? 如果对象是一个 符号 则返回 #t
  • char? 如果对象是一个 字符 则返回 #t
  • string? 如果对象是一个 字符串 则返回 #t
  • number? 如果对象是一个 数字 则返回 #t
  • complex? 如果对象是一个 复数 则返回 #t
  • real? 如果对象是一个 实数 则返回 #t
  • rational? 如果对象是一个 有理数 则返回 #t
  • integer? 如果对象是一个 整数 则返回 #t
  • exact? 如果对象 不是 一个 浮点数 的话则返回 #t
  • inexact? 如果对象是一个 浮点数 的话则返回 #t
   要小心的是空表 '() 是一个表,但不是一个序对
(pair? '()) ; #f 
(list? '())  ; #t 

比较数值

=><<=>= 这些函数都有 任意个数的参数 。如果 参数是按照这些函数的名字排序 的话,函数就返回 #t

(= 1 1 1.0) ; #t
(< 1 2 3) ; #t 
(< 1) ; #t
(<) ; #t 

(= 2 2 2) ; #t 
(< 2 3 3.1) ; #t 
(> 4 1 -0.2) ;#t 

(<= 1 1 1.1) ;#t 

(>= 2 1 1.0) ; #t 

(<= 3 4 3.9) ; #f 

odd?even?positive?negative?zero? 这些函数仅有 一个参数 ,如果这些参数 满足函数名所指示的条件 话就返回 #t

比较字符

比较字符 的时候可以使用 char=?char<?char>?char<=? 以及 char>=? 函数

比较字符串

比较字符串 时,可以使用 string=?string-ci=? 等函数

Next:局部变量

Previous:定义函数

Home:目录