11迭代和包含

for語法體系用來處理序列上的迭代。列表,向量,字符串,比特字符串,輸入端口,哈希表都能被當(dāng)做序列使用。構(gòu)造函數(shù)比如in-range也能纏身序列。
for變種以各種方式積累迭代結(jié)果,但是它們的語法形式相同。

  (for ([id sequence-expr] ...)
    body ...+)

for循環(huán)迭代通過sequence-expr產(chǎn)生的序列。序列的每一個(gè)元素,都會(huì)綁定到id,然后執(zhí)行body代碼。

  >(for ([i '(1 2 3)])
    (display i))
  123
  >(for ([i "abc"])
      (printf "~a..." i))
  a...b...c...
  >(for ([i 4])
      (display i))
  0123

for/list是一種更加racket風(fēng)格的變種。它會(huì)累積方法體的結(jié)果到一個(gè)列表,而不是單純執(zhí)行方法體。更加專業(yè)的術(shù)語,for/list實(shí)現(xiàn)了一種列表包含。
>(for/list ([i '(1 2 3)]
(* i i))
'(1 4 9)
>(for/list ([i "abc"])
i)
'(#\a #\b #\c)
>(for/list ([i 4])
i)
'(0 1 2 3)
for語法的完全形式可以同時(shí)平行的迭代多個(gè)序列,for*內(nèi)嵌迭代而不是平行的執(zhí)行。for系列的語法辯題,都能使用條件來過濾迭代項(xiàng)。

11.1 序列構(gòu)造器

in-range函數(shù)產(chǎn)生了一個(gè)數(shù)字的序列,可以設(shè)置一個(gè)可選的開始值,一個(gè)結(jié)束值(結(jié)束前的最后一個(gè)),一個(gè)可選的步進(jìn)值。使用一個(gè)非負(fù)整數(shù)k直接產(chǎn)生一個(gè)序列的代碼(in-range k)

>(for ([i 3])
    (display i))
012
>(for ([i (in-range 3)])
    (display i))
012
>(for ([i (in-range 1 4])
    (display i))
123
>(for ([i (in-range 1 4 2)])
    (display i))
13
>(for ([i (in-range 1 4 1/2])
     (printf "~a" i))
1 3/2 5/2 3 7/2

in-naturals類似,處理開始數(shù)字必須是一個(gè)非負(fù)整數(shù)(默認(rèn)是0),步進(jìn)值總是1,但是沒有上限。它不會(huì)終止除非異常或者其它的跳出。

>(for ([i (in-naturals)])
    (if (= i 10)
        (error "too much")
        (display i)))

stop-before,stop-after函數(shù)通過一個(gè)序列和一個(gè)謂詞判斷產(chǎn)生一個(gè)新的序列。產(chǎn)生的新序列和原來的序列一樣,但是在謂詞判斷返回true以前或者以后馬上停止。

>(for ([i (stop-before "abc def"
               char-whitespace?)])
         (display i))
abc

in-list,in-vector,in-string明確了產(chǎn)生序列的類型。如果賦值了一個(gè)錯(cuò)誤類型,會(huì)拋出一個(gè)異常。因?yàn)楸苊饬诉\(yùn)行時(shí)的類型分發(fā),代碼的效率更高。

11.2for和for*

更加復(fù)雜的for語句

>(for (clause ...)
    body ...+)
    clause= [id sequence-expr]
               | #:when boolean-expr
               | #:unless boolean-expr

當(dāng)有多個(gè)[id sequence-expr]子句,它會(huì)平行遍歷多個(gè)序列。當(dāng)其中一個(gè)平行序列結(jié)束,整個(gè)遍歷就會(huì)結(jié)束。利用這種特性,結(jié)合in-naturals這種產(chǎn)生無限序列的構(gòu)造器,可以產(chǎn)生索引。

>(for ( [i (in-naturals 1)]
           [chapter '("Intro" "Details" "Conclusion")])
        (printf "Chapter ~a. ~a\n" i chapter))
Chapter 1. Intro
Chapter 2. Details
Chapter 3. Conclusion

for*和for類似,但是內(nèi)嵌迭代而不是平行。
for之于for正如let之于let
#:when boolean-expr形式只有在返回true時(shí),方法體才會(huì)執(zhí)行。在一個(gè)for形式中,使用when會(huì)造成迭代內(nèi)嵌,即使在for里面也是這樣。
#:unless boolean-expr 與when相反。

11.3for/list 和 for*/list

for/list和for有一樣的語法形式,執(zhí)行方法體獲得一個(gè)新列表。
使用#:when可以裁剪結(jié)果列表。
>(for/list ([i (in-naturals 1)]
[chapter '("Intro" "Details" "Conclusion")]
#:when (odd? i))
chapter)
'("Intro" "Conclusion")
#:when 的裁剪功能在for/list更加有用。原始的when表達(dá)式會(huì)產(chǎn)生一個(gè)#<void>值而不是忽略返回值。
'for/list'形式和for*類似,內(nèi)嵌多個(gè)迭代。
>(for
/list ([book '("Guide" "Ref.")]
[chapter '("Intro" "Details")])
(string-append book " " chapter))
'("Guide Intro" "Guide Details" "Ref. Intro" "Ref. Details")
for*/list和for/list的內(nèi)嵌形式并不相同。內(nèi)嵌的for/list會(huì)產(chǎn)生一個(gè)列表的列表,而不是展開的列表。它更像#:when形式造成的內(nèi)嵌。

11.4 fro/vector 和for*/vector

for/vector語法和for/list相似,只是構(gòu)造向量而不是列表。它們都能指定#:length參數(shù)。

>(let ([chapters '("Intro" "Details" "Conclusion")])
       (for/vector #:length (length chapters) ([i (in-naturals 1)]
                                                               [chanpter chapters])
        (string-append (number->string i) ". " chapter)))
'#("1. Intro" "2. Details" "3. Conclusion")

如果length參數(shù)被提供,當(dāng)向量填滿或者迭代完成,迭代自動(dòng)完成。如果length超過請(qǐng)求的迭代,剩下的使用make-vector使用初始化。

11.5for/and和for/or

for/and形式使用and合并迭代,如果結(jié)果是#f則停止。

>(for/and ([chapter '("Intro" "Details" "Conclusion")])
    (equal? chapter "Intro"))
#f

for/or形式使用or合并迭代,如果結(jié)果是#t則停止。

>(for/or ([chanpter '("Intro" "Details" "Conclusion")])
      (equal? chapter "Intro"))
#t

for*/andfor*/or提供相同的功能但是內(nèi)嵌迭代。

11.6 for/first和for/last

for/first形式返回第一次方法體執(zhí)行的結(jié)果,忽略其它迭代。#:when子句在這種形式里更有用。
>(for/list ([chanpter '("Intro" "Details" "Conclusion" "Index")]
#:when (not (equal? chapter "Intro")))
chanpter)
"Details"
如果方法體被執(zhí)行了0次,結(jié)果是#f。
for/last運(yùn)行迭代,返回最后一個(gè)迭代的值。如果沒有迭代,則返回#f。

>(for/last ([chapter '("Intro" "Details" "Conclusion" "Index")
                  #:when (not (equal? chapter "Index"))])
    chapter)
"Conclusion"

for*/first和'for*/last'提供了類似的內(nèi)嵌的功能

11.7for/fold和for*/fold

for/fold是一種很普遍的用來收集迭代結(jié)果的方式。它的語法和for只有稍微的不同,因?yàn)槔奂悠髯兞勘仨氃陂_始的時(shí)候定義。

(for/fold ([accum-id init-expr] ...)
             (clause ...)
  body ..+)

在簡(jiǎn)單的情況下只有一個(gè)[accum-id init-expr]被提供,函數(shù)的運(yùn)行結(jié)果則是最后的accum-id值,它開始的初始值是init-expr。

>(for/fold ([len 0])
                ([chanpter '("Intro" "Conclusion")])
      (+ len (string-length chapter)))
15
>(fro/fold ([prev #f])
                ([i (in-naturals 1)]
                 [chapter '("Intro" "Details" "Details" "Conclusion")]
                  #:when (not (equal? chanpter prev)))
       (printf "~a. ~a\n" i chanpter)
       chapter)
1. Intro
2. Details
4. Conclusion
"Conclusion"

當(dāng)多個(gè)累加器被指定,方法體最后必須產(chǎn)生多個(gè)值,與每個(gè)累加器對(duì)應(yīng)。for/fold本身也會(huì)返回多個(gè)值。

>(for/fold ([prev #f]
                 [counter 1])
                ([chapter '("Intro" "Details" "Details" "Conclusion")]
                 #:when (not (equal? chapter prev)))
    (printf "~a. ~a\n" counter chapter)
    (values chapter 
               (add1 counter)))
1. Intro
2. Details
3. Conclusion
"Conclusion"
4

11.8多值序列

和函數(shù)和表達(dá)式產(chǎn)生多值一樣,序列的迭代也能產(chǎn)生多個(gè)值。比如,哈希表就可以長生一個(gè)兩個(gè)值的迭代。
和let-values可以綁定多個(gè)結(jié)果到多個(gè)標(biāo)識(shí)符,for也可以綁定多值的序列元素到多個(gè)迭代標(biāo)識(shí)

>(for ([k v] #hash(("apple" .1) ("banana" . 3))])
    (printf "~a count: ~a\n" k v))
apple count: 1
banana count: 3

多值綁定能在多個(gè)for變種里使用。

>(for*/list ([k v) #hash(("apple" . 1) ("banana" . 3))]
                 [(i) (in-range v)])
'("apple" "banana" "banana" "banana")

11.9跳出迭代

(for (clause ...)
  body-or-break ... body)
  clause=[id sequence-expr]
        |#:when boolean-expr
        |#:unless boolean-expr
        |break
  body-or-break=body
        |break
  break=#:break boolean-expr
        |#:final boolean-expr

#:break#:final能使用在綁定語句和方法體里。在綁定語句里,#:break作用和'#:unless'很像,但是如果boolean-expr是true,所有序列迭代都會(huì)停止。在方法體里,#:break和在語句里有著相同的效果,它會(huì)阻斷當(dāng)前迭代以后的方法體執(zhí)行。

>(for ([book '("Cuide" "Story" "Reference")]
          #:unless (equal? book "Story")
          [chapter '("intor" "Details" "Conclusion")])
      (printf "~a ~a\n"  book chapter))
Guide Intro
Guide Details
Guide Conclusion
Reference Intro
Reference Details
Reference Conclusion

使用#:break則會(huì)終止整個(gè)迭代

>(for ([book '("Guide" "Story" "Reference")]
          #:break (equal? book "Story")
          [chapter '("Intro" "Details" "Conclusion")])
      (printf "~a ~a\n" book chapter))
Guide Intro
Guide Details
Guide Conclusion
>(for* ([book '("Guide" "Story" "Reference")]
           [chapter '("Intro" "Details" "Conclusion")])
    #:break (and (equal? book "Story")
                        (equal? chanpter "Conclusion"))
    (printf "~a ~a\n" book chapter))
Guide Intro
Guide Details
Guide Conclusion
Story Intro
Story Details

#:final語句和#:break類似,但是不會(huì)馬上終止迭代。它允許執(zhí)行最后一次。

>(for*  ([book '("Guide" "Story" "Reference")]
            [chapter '("Intro" "Details" "Conclusion")])
      #:final (and (equal? book "Story")
                        (equal? chapter "Conclusion")
      (printf "~a ~a\n" book chapter))
Guide Intro
Guide Details
Guide Conclusion
Story Intro
Story Details
Story Conclusion
>(for ([book '("Guide" "Story" "Reference")]
          #:final (equal? book "Story")
          [chanpter '("Intro" "Details" "Conclusion")])
      (printf "~a ~a\n" book chapter))
Guide Intro
Guide Details
Guide Conclusion
Story Intro

11.10迭代效率

理想情況下,for迭代運(yùn)行和你自己手動(dòng)實(shí)現(xiàn)的遞歸調(diào)用一樣快。但是手寫的循環(huán),一般指定了一種特定的數(shù)據(jù),像列表。在這種情況下,手寫循環(huán)直接使用car,cdr,而不是處理各種形式的序列然后分發(fā)他們到合適的迭代器。
for形式也可以達(dá)到手寫循環(huán)的效率當(dāng)提供足夠多的迭代信息。特別的,子句應(yīng)該有其中一個(gè)fast-clause形式。

fast-clause=[id fast-seq]
          |[(id) fast-seq]
          |[(id id) fast-indexed-seq]
          |[(id ...) fast-parallel-seq]

fast-seq=(in-range expr)
    |(in-range expr expr)
    |(in-range expr expr expr)
    |(in-naturals)
    |(in-naturals expr)
    |(in-list expr)
    |(in-vector expr)
    |(in-string expr)
    |(in-bytes expr)
    |(in-value expr)
    |(stop-before fast-seq predicate-expr)
    |(stop-after fast-seq predicate-expr)

fast-indexed-seq=(in-indexed fast-seq)
    |(stop-before fast-indexed-seq predicate-expr)
    |(stop-after fast-indexed-seq predicate-expr)

fast-parallel-seq=(in-parallel fast-seq ...)
    |(stop-before fast-parallel-seq predicate-expr)
    |(stop-after fast-parallel-seq predicate-expr)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容