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?来判断表是否为空。
1 ]=> (null? `()) ;Value: #t 1 ]=> (null? `(1 2 3)) ;Value: #f 1 ]=> (null? `(a b c)) ;Value: #f函数not可用于对谓词取反。此函数只有一个参数且如果参数值为#f则返回#t,反之,参数值为#t则返回#f。if表达式是一个特殊形式,因为它不对所有的参数求值。因为如果predicate为真,则只有then_value部分被求值。另一方面,如果predicate为假,只有else_value部分被求值。
例:首项为a0,增长率r,项数为n的几何增长(geometric progression)数列之和
(define (sum-gp a0 r n) (* a0 (if (= r 1) n (/ (- 1 (expt r n)) (- 1 r))))) ; !! 1 ]=> (define sum-gp (lambda (a0 r n) (* a0 (if (= r 1) n (/ (- 1 (expt r n) (- 1 r))))))) ;Value: sum-gp 1 ]=> (sum-gp 2 1 3) ;Value: 6
通常来说,几何增长数列的求和公式如下:
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表达式。我们将在下一章讨论begin表达式。
and和or是用于组合条件的两个特殊形式。
Scheme中的and和or不同于C语言中的约定。它们不返回一个布尔值(#t或#f),而是返回给定的参数之一。
and具有任意个数的参数,并从左到右对它们求值。
如果某一参数为#f,那么它就返回#f,而不对剩余参数求值。 ??遍历
反过来说,如果所有的参数都不是#f,那么就返回最后一个参数的值。
1 ]=> (and #f 0) ;Value: #f 1 ]=> (or #f 0) ;Value: 0 1 ]=> (and 1 2 3) ;Value: 3 1 ]=> (or 1 2 3) ;Value: 1 1 ]=> (and 1 2 3 #f) ;Value: #f 1 ]=> (or 1 2 3 #f) ;Value: 1 1 ]=> (and #f #f) ;Value: #f 1 ]=> (or #f #f) ;Value: #f 1 ]=> (or #f #f #f) ;Value: #for具有可变个数的参数,并从左到右对它们求值。
它返回第一个不是值#f的参数,而余下的参数不会被求值。 返回#f后的第一个值。 ? ? 遍历
如果所有的参数的值都是#f的话,则返回最后一个参数的值。 ??很自然就是 # F
注意!!
1 ]=> (or #f 34 #f) ;Value: 34 1 ]=> (or #f 23 45 #f) ;Value: 23对比,总结规律
1 ]=> (or #f 12 23 45) ;Value: 12 1 ]=> (or #f 12 34 45 #f) ;Value: 12练习2
编写下面的函数。
一个接受三个实数作为参数的函数,若参数皆为正数则返回它们的乘积。一个接受三个实数作为参数的函数,若参数至少一个为负数则返回它们的乘积。------第一次编写,失败-----
1 ]=> (define p2 (lambda (a b c) (if (and (> a 0) (> b 0) (> c 0) #f) (a * b *c)) #f)) ;Value: p2 1 ]=> (p2 2 3 4) ;Value: #f-----第二次编写,失败---
1 ]=> (define p3 (lambda (a b c) (if ((> a 0) (> b 0) (> c 0)) (a * b * c) (a + b + c)) )) ;Value: p3 1 ]=> (p3 2 3 4) ;The object #t is not applicable. ;To continue, call RESTART with an option number: ; (RESTART 2) => Specify a procedure to use in its place. ; (RESTART 1) => Return to read-eval-print level 1.-------没有思路----肯定有个东西漏掉了
1 ]=> (define p4 (lambda (a b c) (if (and (> a 0) (> b 0) (> c 0)) (a * b * c) (a + b +c)) )) ;Value: p4 1 ]=> (p4 2 3 4) ;The object 2 is not applicable. ;To continue, call RESTART with an option number: ; (RESTART 2) => Specify a procedure to use in its place. ; (RESTART 1) => Return to read-eval-print level 1.
尽管所有的分支都可以用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之后的predicates和clauses不会被求值。???
如果所有的predicates_i都是假的话,则返回cluase_else。
在一个子句中,你可以写数条S-表达式,而clause的值是最后一条S-表达式。
基本函数eq?、eqv?、equal?具有两个参数,用于检查这两个参数是否“一致”。这三个函数之间略微有些区别。
eq?该函数比较两个对象的地址,如果相同的话就返回#t。
例如,(eq? str str)返回#t,因为str本身的地址是一致的。
与此相对的,因为字符串”hello”和”hello”被储存在了不同的地址中,函数将返回#f。
不要使用eq?来比较数字,因为不仅在R5RS中,甚至在MIT-Scheme实现中,它都没有指定返回值。使用eqv?或者=替代。
eqv?该函数比较两个存储在内存中的对象的类型和值。
如果类型和值都一致的话就返回#t。
对于过程(lambda表达式)的比较依赖于具体的实现。
这个函数不能用于类似于表和字符串一类的序列比较,因为尽管这些序列看起来是一致的,但它们的值是存储在不同的地址中。
equal?该函数用于比较类似于表或者字符串一类的序列。
1 ]=> (define str "hello Schemer") ;Value: str 1 ]=> str ;Value 18: "hello Schemer" 1 ]=> (eq? str str) ;Value: #t 1 ]=> (str) ;The object "hello Schemer" is not applicable. ;To continue, call RESTART with an option number: ; (RESTART 2) => Specify a procedure to use in its place. ; (RESTART 1) => Return to read-eval-print level 1. 2 error> ^G ;Quit! 1 ]=> str ;Value 18: "hello Schemer" 1 ]=> (eq? "hello Schemer" "hello Schemer") ;Value: #f 1 ]=> (eqv? 1 1) ;Value: #t 1 ]=> (eqv? 1 1.0) ;Value: #f 1 ]=> (eqv? (1 2 3) (1 2 3)) ;The object 1 is not applicable. ;To continue, call RESTART with an option number: ; (RESTART 2) => Specify a procedure to use in its place. ; (RESTART 1) => Return to read-eval-print level 1. 2 error> (eqv? (list 1 2 3) (list 1 2 3)) ;Value: #f 1 ]=> (equal? (1 2 3) (1 2 3)) ;The object 1 is not applicable. ;To continue, call RESTART with an option number: ; (RESTART 2) => Specify a procedure to use in its place. ; (RESTART 1) => Return to read-eval-print level 1. 2 error> ^G ;Quit! 1 ]=> (equal? (list 1 2 3) (list 1 2 3)) ;Value: #t 1 ]=> (equal? "hello" "hello") ;Value: #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。
=、>、<、<=、>=这些函数都有任意个数的参数。如果参数是按照这些函数的名字排序的话,函数就返回#t。
odd?、even?、positive?、negative?、zero?这些函数仅有一个参数,如果这些参数满足函数名所指示的条件话就返回#t。
在比较字符的时候可以使用char=?、char<?、char>?、char<=?以及char>=?函数。具体的细节请参见R6RS。
算法语言Scheme修订6报告 R6RS简体中文翻译,https://r6rs.mrliu.org/
比较字符串时,可以使用string=?和string-ci=?等函数。具体细节请参见R6RS。
转载于:https://www.cnblogs.com/yiweshen/p/11230328.html