Yet Another Scheme Tutorial 02

分支

 

if 表达式

if表达式将过程分为两个部分。if的格式以下:算法

(if predicate then_value else_value)

  若是predicate部分为真,那么then_value部分被求值,不然else_value部分被求值,而且求得的值会返回给if语句的括号外。app

  true是除false之外的任意值,true使用#t表示,false#f表示函数

  在R5RS中,false#f)和空表(’())是两个不一样的对象。然而,在MIT-Scheme中,这两个为同一对象。ui

  这个不一样多是历史遗留问题,在之前的标准——R4RS中,#f’()被定义为同一对象。lua

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

1 ]=> (null? `())

;Value: #t

1 ]=> (null? `(1 2 3))

;Value: #f

1 ]=> (null? `(a b c))

;Value: #f

 

函数可用于对谓词取反。此函数只有一个参数且若是参数值为则返回,反之,参数值为则返回。
表达式是一个特殊形式,由于它不对全部的参数求值。
由于若是为真,则只有部分被求值。
另外一方面,若是为假,只有部分被求值。not#f#t#t#fifpredicatethen_valuepredicateelse_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

 

一般来讲,几何增加数列的求和公式以下:code

a0 * (1 - r^n) / (1 - r)                      (r ≠ 1)
a0 * n                                        (r = 1)
若是表达式对全部参数求值的话,那么有注释的那行就算在时也会被求值,
这将致使产生一个“除数为0”的错误。
if;!!r=1

你也能够省去else_value项。这样的话,当predicate为假时,返回值就没有被指定。对象

若是你但愿当predicate为假时返回#f,那么就要明确地将它写出来。blog

then_valueelse_value都应该是S-表达式

若是你须要反作用,那么就应该使用begin表达式。咱们将在下一章讨论begin表达式。

 

and 和 or (重难点)

  andor是用于组合条件的两个特殊形式。

  Scheme中的andor不一样于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: #f

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

它返回第一个不是值#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.

 

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-表达式。

 

作出判断的函数

基本函数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。

相关文章
相关标签/搜索