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。

相關文章
相關標籤/搜索