• Yet Another Scheme Tutorial 02


    分支

    if 表达式

    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_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。

  • 相关阅读:
    困难的图论
    [Poi2011]Meteors
    四维偏序
    bzoj2738矩阵乘法
    创建线程的三种方式
    java邮件发送
    Nginx配置文件分析
    如何理解java反射?
    正则表达式
    jenkins新手入门教程
  • 原文地址:https://www.cnblogs.com/yiweshen/p/11230328.html
Copyright © 2020-2023  润新知