<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC=2] ## 8.1?簡介 **高階函數(Higher Order Function)**是一種以函數為參數的函數。它們都被用于**映射(mapping)**、**過濾(filtering)**、**歸檔(folding)**和**排序(sorting)**表。高階函數提高了程序的模塊性。編寫對各種情況都適用的高階函數與為單一情況編寫遞歸函數相比,可以使程序更具可讀性。比如說,使用一個高階函數來實現排序可以使得我們使用不同的條件來排序,這就將排序條件和排序過程清楚地劃分開來。函數`sort`具有兩個參數,其一是一個待排序的表,其二是**定序(Ordering)**函數。下面展示了按照大小將一個整數表正序排序。`<`函數就是(本例中的)兩數的定序函數。 ~~~ (sort '(7883 9099 6729 2828 7754 4179 5340 2644 2958 2239) <) ;? (2239 2644 2828 2958 4179 5340 6729 7754 7883 9099) ~~~ 另一方面,按照每個數末兩位的大小排序可以按下面的方式實現: ~~~ (sort '(7883 9099 6729 2828 7754 4179 5340 2644 2958 2239) (lambda (x y) (< (modulo x 100) (modulo y 100)))) ;? (2828 6729 2239 5340 2644 7754 2958 4179 7883 9099) ~~~ 正如這里所演示的,像**快速排序(Quick Sort)**、**歸并排序(Merge Sort)**等排序過程,將定序函數完全分離開來提高了代碼的復用性。 在本節中,我將講解預定義的高階函數,然后介紹如何定義高階函數。由于Scheme并不區別過程和其它的數據結構,因此你可以通過將函數當作參數傳遞輕松的定義自己的高階函數。 實際上,Scheme中預定義函數的本質就是高階函數,因為Scheme并沒有定義塊結構的語法,因此使用`lambda`表達式作為一個塊。 ## 8.2?映射 映射是將同樣的行為應用于表所有元素的過程。R5RS定義了兩個映射過程:其一為返回轉化后的表的`map`過程,另一為注重副作用的`for-each`過程。 ### 8.2.1?map `map`過程的格式如下: ~~~ (map procedure list1 list2 ...) ~~~ `procedure`是個與某個過程或`lambda`表達式相綁定的符號。作為參數的表的個數視`procedure`需要的參數而定。 例: ~~~ ; Adding each item of '(1 2 3) and '(4 5 6). (map + '(1 2 3) '(4 5 6)) ;? (5 7 9) ; Squaring each item of '(1 2 3) (map (lambda (x) (* x x)) '(1 2 3)) ;? (1 4 9) ~~~ ### 8.2.2?for-each `for-each`的格式與`map`一致。但`for-each`并不返回一個具體的值,只是用于副作用。 例: ~~~ (define sum 0) (for-each (lambda (x) (set! sum (+ sum x))) '(1 2 3 4)) sum ;? 10 ~~~ > 練習1 > > 用`map`編寫下面的函數: > > 1. 一個將表中所有元素翻倍的函數; > 2. 一個將兩個表中對應位置元素相減的函數; ## 8.3?過濾 盡管過濾函數并沒有在R5RS中定義,但MIT-Scheme實現提供了`keep-matching-items`和`delete-matching-item`兩個函數。其它實現中應該有類似的函數。 ~~~ (keep-matching-items '(1 2 -3 -4 5) positive?) ;? (1 2 5) ~~~ > 練習2 > > 編寫下列函數: > > 1. **濾取(Filtering Out)**出一個表中的偶數; > 2. 濾取出不滿足`10 ≤ x ≤ 100`的數; ## 8.4?歸檔 盡管在R5RS中沒有定義歸檔函數,但MIT-Scheme提供了`reduce`等函數。 ~~~ (reduce + 0 '(1 2 3 4)) ;? 10 (reduce + 0 '(1 2)) ;? 3 (reduce + 0 '(1)) ;? 1 (reduce + 0 '()) ;? 0 (reduce + 0 '(foo)) ;? foo (reduce list '() '(1 2 3 4)) ;? (((1 2) 3) 4) ~~~ > 練習3 > > 1. 編寫一個將表中所有元素平方的函數,然后求取它們的和,最后求和的平方根。 ## 8.5?排序 盡管R5RS中沒有定義排序函數,但MIT-Scheme提供了`sort`(實為`merge-sort`實現)和`quick-sort`函數。 ~~~ (sort '(3 5 1 4 -1) <) ;? (-1 1 3 4 5) ~~~ > 練習4 > > 編寫下列函數 > > 1. 以`sin(x)`的大小升序排序; > 2. 以表長度降序排序; ## 8.6?apply函數 `apply`函數是將一個過程應用于一個表(譯注:將表展開,作為過程的參數)。此函數具有任意多個參數,但首參數和末參數分別應該是一個過程和一個表。雖然乍看之下不然,但這個函數的確非常方便。 ~~~ (apply max '(1 3 2)) ;? 3 (apply + 1 2 '(3 4 5)) ;? 15 (apply - 100 '(5 12 17)) ;? 66 ~~~ > 練習5 > > 用`apply`編寫練習3中的函數。 ## 8.7?編寫高階函數 自己編寫高階函數非常容易。這里用`member-if`、`member`和`fractal`演示。 ### 8.7.1?member-if和member `member-if`函數使用一個謂詞和一個表作為參數,返回一個子表,該子表的`car`部分即是原列表中首個滿足該謂詞的元素。`member-if`函數可以像下面這樣定義: ~~~ (define (member-if proc ls) (cond ((null? ls) #f) ((proc (car ls)) ls) (else (member-if proc (cdr ls))))) (member-if positive? '(0 -1 -2 3 5 -7)) ;? (3 5 -7) ~~~ 接下來,`member`函數檢查特定元素是否在表中,該函數編寫如下。函數需要三個參數,其一為用于比較的函數,其二為特定項,其三為待查找表。 ~~~ (define (member proc obj ls) (cond ((null? ls) #f) ((proc obj (car ls)) ls) (else (member proc obj (cdr ls))))) (member string=? "hello" '("hi" "guys" "bye" "hello" "see you")) ;? ("hello" "see you") ~~~ ### 8.7.2?不規則曲線 生成像C曲線、龍曲線等不規則曲線可以通過在兩個點中插入一個點來實現 which are generated by inserting a point(s) between two points according to a positioning function can be separated into two parts: a common routine to generate fractal curves and a positioning function. 。代碼實現如下: ~~~ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; frac.scm ;;; ;;; draw fractal curves ;;; by T.Shido ;;; on August 20, 2005 ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 平面直角坐標系上的點通過序對來表示,其中car部分和cdr部分分別代表 ;;; x坐標和y坐標。 ;;; 函數_x和_y用來取得坐標,point用來建立一個點。 (define _x car) (define _y cdr) (define point cons) ;;; (rappend ls0 ls1) ;;; (rappend '(1 2 3) '(4 5 6)) -> (3 2 1 4 5 6) ;;; ;;; 接受兩個表作為參數,將第一個表反轉后與第二個表連接起來。 (define (rappend ls0 ls1) (let loop((ls0 ls0) (ls1 ls1)) (if (null? ls0) ls1 (loop (cdr ls0) (cons (car ls0) ls1))))) ;;; (devide p1 p2 r) ;;; dividing?p1?and?p2?internally by the ratio?r. (define (divide p1 p2 r) (point (+ (* r (_x p1)) (* (- 1.0 r) (_x p2))) (+ (* r (_y p1)) (* (- 1.0 r) (_y p2))))) ;;; (print-curve points fout) ;;; 將點輸出至文件。將一系列點points按一行一個點得格式輸出至fout代 ;;; 表的文件 (define (print-curve points fout) (with-output-to-file fout (lambda () (for-each (lambda (p) (display (_x p)) (display " ") (display (_y p)) (newline)) points)))) ;;; (fractal?proc?n?points?fout) ;;; 創建分型圖形的高階函數。其中,proc是定位函數,n是重復次數, ;;; points是初始點構成的表,fout是輸出文件的文件名。 ;;; 函數由兩個叫做loop和iter的循環構成。loop對數據表做n次插入。 ;;; The?iter?adds new points to the data list using the positioning function. In short,?fractal?generates curves by repeating?iter?for?n?times. The positioning function?proc?takes two points as arguments and returns a list of the first point and the interpolated point. (define (fractal proc n points fout) (let loop ((i 0) (points points)) (if (= n i) (print-curve points fout) (loop (1+ i) (let iter ((points points) (acc '())) (if (null? (cdr points)) (reverse! (cons (car points) acc)) (iter (cdr points) (rappend (proc (first points) (second points)) acc))))))) 'done) ;;; (c-curve p1 p2) ;;; C-曲線的定位函數 (define (c-curve p1 p2) (let ((p3 (divide p1 p2 0.5))) (list p1 (point (+ (_x p3) (- (_y p3) (_y p2))) (+ (_y p3) (- (_x p2) (_x p3))))))) ;;; (dragon-curve p1 p2) ;;; 龍曲線的定位函數 (define dragon-curve (let ((n 0)) (lambda (p1 p2) (let ((op (if (even? n) + -)) (p3 (divide p1 p2 0.5))) (set! n (1+ n)) (list p1 (point (op (_x p3) (- (_y p3) (_y p2))) (op (_y p3) (- (_x p2) (_x p3))))))))) ;;; (koch p1 p2) ;;; Koch曲線的定位函數 (define (koch p1 p2) (let ((p3 (divide p1 p2 2/3)) (p4 (divide p1 p2 1/3)) (p5 (divide p1 p2 0.5)) (c (/ (sqrt 3) 2))) (list p1 p3 (point (- (_x p5) (* c (- (_y p4) (_y p3)))) (+ (_y p5) (* c (- (_x p4) (_x p3))))) p4))) ~~~ 下面的代碼演示了如何生成分型曲線。源代碼在這里。使用之前請先編譯,以節省計算時間。 ~~~ (compile-file "frac.scm") (load "frac") ;; C-Curve (fractal c-curve 14 '((0 . 0) (2 . 3)) "c14.dat") ;Value: done ;; Dragon-Curve (fractal dragon-curve 14 '((0 . 0) (1 . 0)) "d14.dat") ;Value: done ;; Koch-Curve (fractal koch 5 '((0 . 0) (1 . 0)) "k5.dat") ;Value: done ~~~ X坐標和Y坐標都存儲在名字形如`*.dat`的文件中。你可以使用你喜歡的制圖程序來繪制。圖表1-3都是用gnuplot繪制的。 > 練習 6 > > 1. 自己實現`keep-matching-items`。 > 2. 自己實現`map`。接受不止一個表作為參數可能有點困難。剩余的參數是通過帶點得序對`(.)`來定義的。其`cdr`部分以表的形式傳遞給函數。 例: my-list?`scheme (define (my-list . x) x)?`多說一句,你需要`apply`函數。 ## 8.8?小結 本章中,我講解了高階函數。正如在生成分形圖形體現的那樣,高階函數增強了模塊化成都。你可以很容易地定義高階函數。當你編寫函數時,更要在乎將其實現為更抽象的高階函數,這樣可以讓你的代碼能夠**復用(reusable)**。 在下一章節中,我會介紹IO。 ## 8.9?習題解答 ### 8.9.1?答案1 ~~~ ; 1 (define (double ls) (map (lambda (x) (* x 2)) ls)) ; 2 (define (sub ls1 ls2) (map - ls1 ls2)) ~~~ ### 8.9.2?答案2 ~~~ ; 1 (define (filter-even ls) (keep-matching-items ls even?)) ; 2 (define (filter-10-100 ls) (keep-matching-items ls (lambda (x) (<= 10 x 100)))) ~~~ ### 8.9.3?答案3 ~~~ (define (sqrt-sum-sq ls) (sqrt (reduce + 0 (map (lambda (x) (* x x)) ls)))) ~~~ ### 8.9.4?答案4 ~~~ ; 1 (define (sort-sin ls) (sort ls (lambda (x y) (< (sin x) (sin y))))) ; 2 (define (sort-length ls) (sort ls (lambda (x y) (> (length x) (length y))))) ~~~ ### 8.9.5?答案5 ~~~ (define (sqrt-sum-sq-a ls) (sqrt (apply + (map (lambda (x) (* x x)) ls)))) ~~~ ### 8.9.6?答案6 ~~~ ; 1 (define (my-keep-matching-items ls fn) (cond ((null? ls) '()) ((fn (car ls)) (cons (car ls) (my-keep-matching-items (cdr ls) fn))) (else (my-keep-matching-items (cdr ls) fn)))) ; 2 (define (my-map fun . lss) (letrec ((iter (lambda (fun lss) (if (null? lss) '() (cons (fun (car lss)) (iter fun (cdr lss)))))) (map-rec (lambda (fun lss) (if (memq '() lss) '() (cons (apply fun (iter car lss)) (map-rec fun (iter cdr lss))))))) (map-rec fun lss))) (my-map + '(1 2 3) '(10 20 30) '(100 200 300)) ;? (111 222 333) ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看